静态代理、动态代理的区别 以及 JVM动态代理与Cglib动态代理的实现与区别

静态代理、动态代理的区别 以及 JVM动态代理与Cglib动态代理的实现与区别

静态代理&动态代理

  • 设计模式中有一种模式就叫做代理模式,分成动态代理和静态代理
    • 静态代理在编译的时候就将接口,被代理类,代理类等确定下来了,程序运行之前.class文件就已经生成了
    • 动态代理在运行的时候动态生成
  • 代理类主要负责为为拖累预处理消息,过滤消息,转发消息,事后处理消息,让我们在访问对象的时候是通过代理对象进行访问的,为访问对象的时候进行代码增强,解除耦合
  • 动态代理对于静态代理的好处:态代理可以对被代理类的所有方法进行统一的管理,不需要为代理类中的每一个方法进行代理.

JVM 动态代理

java动态代理实现与原理详细分析: https://www.cnblogs.com/gonjan-blog/p/6685611.html

三个基本对象

  • 被代理对象:真实的对象,需要被代理实现的对象
  • 代理对象:真实对象的代理对象,真实对象的代理方法都由代理对象进行代理
  • 抽象对象:真实对象和代理对象的共同接口,这样在调用真实对象的地方都可以使用代理对象

代码实现

  1. 继承InvocationHandler接口,作为实现动态代理的代理类,持有代理类的一个实例
  2. Proxy.newProxyInstance(ClassLoader loader, Class[] class, InvocationHandler hanlder)
    1. loader对象: 抽象对象的类加载器
    2. class数组: 是实现接口对象实现的接口数组
    3. 代理类handler
    4. 返回的是代理对象,进行类型强转为抽象对象
  3. 调用的代理对象的方法时就是方法增强的方法(AOP)

注意事项

  • jvm是通过实现同一个接口来实现动态代理,所以一定要有接口才能够使用

JVM实现动态代理的原理

  • 主要运用了java中的反射机制
  • 先创建了一个被代理对象,将代理对象传入了handler当中,创建代理对象的时候,将handler作为参数,执行方法的时候统一被替换成invoke方法

Proxy.newProxyInstance方法源码分析

  1. 通过getProxyClass0(loader, intfs)方法产生代理类
    1. 代理类继承了Proxy对象,实现了抽象对象的接口对象,new Proxy(InvocationHandler handler),将handler对象传入进来
    2. 代理类中使用了Class.forName().getMethod获取了抽象类的所有方法
      eg: Method m1 = Class.forName().getMethod(“test”,new Class[0])
    3. 将抽象对象中的所有非private方法都重写了一遍,
      eg: void test () {this.handler.invoke(this,m1,null)}

Cglib 动态代理

CGLIB动态代理实现原理: https://blog.csdn.net/yhl_jxy/article/details/80633194

代码实现

// 用于生成动态子类
Enhancer enhancer = new Enhancer();
// 将被代理对象作为参数传入作为生成的被代理对象父类
enhancer.setSuperclass(ProxyModel.class);
//  代理方法实现 MethodInterceptor 对所有的方法进行代理   CallbackFilter 对单个方法进行代理
enhancer.setCallback(new MethodInterceptor() {
    @Override
    public Object intercept( Object o, Method method, Object[] objects, MethodProxy methodProxy){
        log.info("开始代理");
        Object object = methodProxy.invokeSuper(o, objects);
        log.info("代理结束");
        return object;
   }
});
// 生成代理对象
ProxyModel model = (ProxyModel) enhancer.create();
  • 和JVM的实现一样,通过动态生成.class文件,继承方法,然后通过调用callback对象来执行代码

注意事项

  • Cglib是通过继承被代理类来实现动态代理的,所以被代理类不能被final修饰,不然会抛出异常
  • 如果被代理类中有final类型的方法,将会直接走被代理类的方法,不会走代理

JVM与Cglib实现动态代理的区别

  • JDK 使用的是拦截器加上反射机制生成一个实现代理接口的匿名类,调用具体方法前使用invokeHandler来处理, Cglib通过ASM开源包,将代理对象类的class文件加载进来,通过修改字节码生成子类
  • JDK和Cglib的选用
    • 实现了接口的话两者都可以使用
    • 如果没有使用接口的话使用Cglib
    • 假如类是使用Final 类型修饰的话不能使用Cglib,无法继承,只能使用JVM的动态代理
  • 两者效率对比:
    • jdk6,7时大量调用jdk动态代理效率不如cglib,jdk8时jdk效率高于cglib
    • 调用次数少的情况下jdk动态代理的效率还是高的

你可能感兴趣的:(java)