设计模式之代理模式

152 阅读2分钟

设计模式之代理模式

定义

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

特点:

  1. 真实对象职责清晰
  2. 客户端直接调用代理端,保护真实对象

UML结构图

在这里插入图片描述
对图中三个部分进行解释:

  • Subject:抽象角色,定义操作
  • Proxy:代理对象,持有真实对象;客户端直接操作对象
  • RealSubject:真实对象,只关心自己实现的内容

分类

静态代理

  1. 服务类
/**
 * 需要代理的方法
 */
public interface Subject {
    void execute();
}
  1. 实际对象
/**
 * 实际的对象
 */
public class RealSubject implements Subject {
    @Override
    public void execute() {
        System.out.println("RealSubject execute");
    }
}
  1. 代理类
public class Proxy implements Subject {
    private Subject subject;

    public Proxy(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void execute() {
        System.out.println("Proxy execute");
        if (subject != null) {
            subject.execute();
        }
    }
}

小结:

  1. 每个服务都必须创建一个代理对象。

动态代理

  1. 服务类
/**
 * 需要代理的方法
 */
public interface Subject {
    void execute();
}
  1. Handler-用于生成代理对象
/**
 * InvocationHandler 生成代理对象
 */
public class DynamicProxyHandler implements InvocationHandler {

    private Subject subject;

    public DynamicProxyHandler(Subject subject) {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("DynamicProxyHandler invoke");
        return method.invoke(subject, args);
    }
}

小结: 依赖于接口 注意 Proxy.newProxyInstance()方法接受三个参数:

  1. ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
  2. Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
  3. InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法

Cglib代理

注意:使用前需提前导入ASM和Cglib的jar包。

CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。脱离了接口以及代理类

  1. 真实对象
/**
 * 真实对象
 */
public class SubjectCglib {
    public void execute() {
        System.out.println("Subject execute");
    }
}
  1. Cglib拦截器
/**
 * Cglib 方法拦截器
 */
public class CglibInterceptor implements MethodInterceptor {

    public <T> T createProxy(Class<T> targetClass) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(targetClass);
        enhancer.setCallback(this);
        return (T) enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("CglibInterceptor intercept before");
        Object object = methodProxy.invokeSuper(obj, args);
        System.out.println("CglibInterceptor intercept after");
        return object;
    }
}

小结:

  1. 无需代理对象及接口
  2. 效率比动态代理高,时间花费更大
  3. 单例对象使用Cglib更合适,反之,使用动态代理
  4. 无法对final修饰的类进行操作

使用

public class Main {

    public static void main(String[] args) {
        // write your code here
        /**
         * 静态代理
         */
        Subject subject = new RealSubject();
        Proxy proxy = new Proxy(subject);
        proxy.execute();


        /**
         * 动态代理
         */
        Subject subjectImpl = new SubjectImpl();
        DynamicProxyHandler handler = new DynamicProxyHandler(subjectImpl);
        //DynamicProxyHandler handler = new DynamicProxyHandler();
        Subject dyProxy = (Subject) java.lang.reflect.Proxy.
                newProxyInstance
                        (
                                SubjectImpl.class.getClassLoader(),
                                SubjectImpl.class.getInterfaces(),
                                handler
                        );

        dyProxy.execute();

        // ------------------------------------------(静动态代理-都需要声明接口)---------------------------------------------------------//


        /**
         * Cglib 代理
         */
        CglibInterceptor interceptor = new CglibInterceptor();
        SubjectCglib subjectCglib2 =
                 interceptor.createProxy(SubjectCglib.class);
        subjectCglib2.execute();
    }
}