结合上面的演示,我们小结一下 CGLIB 动态代理的实现:
1.实现一个MethodInterceptor,方法调用被转发到该类的 intercept() 方法。
2.使用 Enhancer 获取代理对象,并调用对应的方法。
JDK Vs CgLibJava 1.3 后,提供了动态代理技术,允许我们开发者在运行期创建接口的代理实例,后来这项技术被用到了很多地方(比如 Spring AOP)。
JDK 动态代理主要对应到 java.lang.reflect 包下边的两个类:Proxy 和 InvocationHandler。
其中 InvocationHandler 是一个接口,可以通过实现该接口定义横切逻辑。
举个例子,在方法执行前后打印的日志(这里只是为了说明,实际应用一般不会只是简单的打印日志,一般用于日志、安全、事务等场景),并通过「反射机制」调用目标类的代码,动态地将横切逻辑和业务逻辑编织在一起。
JDK 动态代理有一个限制:它只能为接口创建代理实例。
对于没有通过接口定义业务方法的类,如何创建动态代理实例呢?答案就是 CGLib。
CGLIB(Code Generation Library))是一个底层基于 ASM 的字节码生成库,它允许我们在「运行时」修改和动态生成字节码。
CGLIB 通过继承方式实现代理,在子类中采用方法拦截的方式拦截所有父类方法的调用并顺势织入横切逻辑。
JDK 和 CGLib 动态代理区别 1. JDK 动态代理实现原理通过实现 InvocationHandler 接口创建自己的调用处理器
通过为 Proxy 类指定 ClassLoader 对象和一组 interface 创建动态代理
通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数传入
JDK 动态代理是面向接口的代理模式,如果被代理目标没有接口则无能为力。
例如,Spring 通过 Java 的反射机制生产被代理接口的新的匿名实现类,重写了 AOP 的增强方法。
2. CGLib 动态代理原理利用 ASM 开源包,对代理对象类的 class 文件加载进来,通过修改其字节码生成子类来处理。
3. 两者对比JDK 动态代理是面向接口的;
CGLib 动态代理是通过字节码底层继承代理类来实现,如果被代理类被 final 关键字所修饰,则无法被代理。
4.适用场景
如果被代理的对象是个实现了接口的实现类,那么可以使用 JDK 动态代理。
例如,Spring 会使用 JDK 动态代理来完成操作(Spirng 默认采用)
如果被代理的对象没有实现接口,只有实现类,那么只能使用 CGLib 实现动态代理(JDK 不支持)。
例如,被代理对象是没有接口的实现类,Spring 强制使用 CGLib 实现的动态代理。
性能对比网上有人对于不通版本的 jdk 进行了测试,经过多次试验,测试结果大致如下:
在 JDK 1.6 和 1.7 时,JDK 动态代理的速度要比 CGLib 要慢,但是并没有某些书上写的10倍差距那么夸张。
在 JDK 1.8 时,JDK 动态代理的速度比 CGLib 快很多。
[idea] 很多时候,性能差异不一定是我们选择某种方式的绝对因素,我们更应该去考虑该技术适用的场景。
例如,我们应用中绝大多数的性能差异可能主要在集中在磁盘 I/O,网络带宽等因素,动态代理这点性能差异可能只是占了非常小的比例。
Referencehttps://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html
https://www.cnblogs.com/CarpenterLee/p/8241042.html
https://blog.csdn.net/shallynever/article/details/103351299