首页 > 技术文章 > JDK动态代理和CGlib动态代理

Nilekai 2021-02-04 23:36 原文

代理模式

代理模式为另一个对象提供一个替身或者占位符以控制对这个对象的访问。使用代理模式创建代理对象,让代理对象控制对某对象的访问,被代理的对象可以是远程的对象,创建开销大的对象或者是需要安全控制的对象。

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

代理模式类图

静态代理

静态代理:由程序员使用工具或者编码生成.java代理类,然后再编译代理类,所以静态就是再程序运行前就已经存在代理类的字节码文件,代理类和委托类在运行前就已经确定。

接口类

public interface Subject {
    void method();
}

目标类

public class RealSubject implements Subject {
    @Override
    public void method() {
        System.out.println("RealSubject");
    }
}

代理类

public class ProxySubject implements Subject {
    private Subject real;

    public ProxySubject(Subject real) {
        this.real = real;
    }


    @Override
    public void method() {
        real.method();
    }
}

优缺点

优点:实现简单、容易理解

缺点:1.当目标类增多时,代理类也要成倍增加,代理类增多,编码工作量加大。2 当接口功能(方法)增多时,代理类也需要做相应的改变,增加了代码维护的复杂度。

动态代理

动态代理:在程序运行期间由JVM根据反射等机制动态生成代理类的字节码并加载,所以项目中不存在代理类源码。

接口

public interface Subject {
    void method();
}

目标类

public class RealSubject implements Subject {
    @Override
    public void method() {
        System.out.println("RealSubject");
    }
}

JDK动态代理实现

​ JDK动态代理是基于接口实现,所以目标类首先要要实现接口,如果没有接口,则无法生成代理类。

  1. 创建一个实现InvocationHandler的类A,并实现invoke()方法
  2. 创建目标类,使A持有目标类的实例
  3. 通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)创建代理对象
  4. 通过代理对象执行目标方法,代理对象将会执行A实例的invoke()方法,通过Method类的invoke方法反射执行目标方法
public class ProxyFactory implements InvocationHandler {
    private Subject real;

    public ProxyFactory(Subject real) {
        this.real = real;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //日志、权限、性能监控等逻辑
        return  method.invoke(real,args);
    }
}
public class ProxyMain {
    public static void main(String[] args) {
        Subject real = new RealSubject();
        InvocationHandler ih = new ProxyFactory(real);
        Subject sub = (Subject)Proxy.newProxyInstance(real.getClass().getClassLoader(),real.getClass().getInterfaces(),ih);
        sub.method();
    }

}

CGlib动态代理实现

​ CGlib是基于生成代理类的子类,所以不能对final类以及final方法进行代理

public class SubjectInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        return methodProxy.invokeSuper(o, objects);
    }
}

public class ProxyMain {
    public static void main(String[] args) {
  	    Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new SubjectInterceptor());
        Subject cglibSub = (Subject)enhancer.create();
        cglibSub.method();

}

推荐阅读