设计模式-代理模式


定义

代理模式又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问

场景

  • 客户端无法持有真正的业务对象,必须使用代理才能访问
  • 业务对象只关注真正的业务,在任务开始前后需要做一些处理
  • 代理对象需要做一些权限之类的鉴别,以判断客户端是否可以继续使用真正的业务
  • 在进行真正业务之前对消息进行处理

1.静态代理

public interface Subject {
public void doSomething(String context);
}

public class RealSubject implements Subject {

@Override
public void doSomething(String context) {
System.out.println("Hi,"+context);
}

public class MarkSentiseProxy implements Subject {

Subject subject = null;
public MarkSentiseProxy(Subject subject) {
this.subject = subject;
}
@Override
public void doSomething(String context) {
context = filterContext(context);
this.subject.doSomething(context);
}

/**
* 将敏感内容password替换成*
* @param context
* @return
*/
public String filterContext(String context) {
return context.replace("password", "********");
}
}

public class ProxyMain {

public static void main(String[] args) {
Subject subject = new RealSubject();
subject = new MarkSentiseProxy(subject);
subject.doSomething("go to work!");
subject.doSomething("show password");
}

 JDK生成的代理类为final类,所以无法生成子类

 上面这个例子在真正业务之前过滤掉敏感字符password为*****

由此可见代理的有点

  • 职责清晰:业务只关心自己真正的业务,而其他一些逻辑则留给代理完成
  • 高扩展性:增加具体主题角色,不需要修改代理类;修改代理类逻辑不需要修改具体类(如:修改过滤规则)

但是静态代理需要为不同的接口实现不同的代理类,所以需要使用动态代理

2.动态代理

动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象。

2.1JDK动态代理

使用java.lang.reflect.InvocationHandler实现

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class JDKProxy implements InvocationHandler {
Object target = null;
public JDKProxy(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String context = (String)args[0];
Object obj = method.invoke(target, context.replace("password", "*************"));
return obj;
}

import java.lang.reflect.Proxy;

public class ProxyMain {

public static void main(String[] args) {
Subject subject = new RealSubject();
subject = new MarkSentiseProxy(subject);
subject.doSomething("go to work!");
subject.doSomething("show password");

JDKProxy proxy = new JDKProxy(new RealSubject());
subject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class},
proxy);
subject.doSomething("go to work!");
subject.doSomething("show password");
}

但是这种1.对所有的接口进行代理

               2.只能对接口进行代理

2.2 Cglib代理

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CgLibProxy implements MethodInterceptor{
Object target = null;

public CgLibProxy(Object target) {
this.target = target;
}

//给目标对象创建一个代理对象
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();

}

@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
return arg1.invoke(target, ((String)arg2[0]).replaceAll("password", "********"));
}

 cglib需要引入的jar


cglib
cglib
3.1