天天看点

spring jdk动态代理、Cglib动态代理和LoadTimeWeaver(LTW)的应用选择

在Java 语言中,从织入切面的方式上来看,存在三种织入方式:编译期织入、类加载期织入和运行期织入。编译期织入是指在Java编译期,采用特殊的编译器,将切面织入到Java类中;而类加载期织入则指通过特殊的类加载器,在类字节码加载到JVM时,织入切面;运行期织入则是采用CGLib工具或JDK动态代理进行切面的织入。 

AspectJ采用编译期织入和类加载期织入的方式织入切面,是语言级的AOP实现,提供了完备的AOP支持。它用AspectJ语言定义切面,在编译期或类加载期将切面织入到Java类中。 

AspectJ提供了两种切面织入方式,第一种通过特殊编译器,在编译期,将AspectJ语言编写的切面类织入到Java类中,可以通过一个Ant或Maven任务来完成这个操作;第二种方式是类加载期织入,也简称为LTW(Load Time Weaving)。 

如何使用Load Time Weaving?首先,需要通过JVM的-javaagent参数设置LTW的织入器类包,以代理JVM默认的类加载器;第二,LTW织入器需要一个 aop.xml文件,在该文件中指定切面类和需要进行切面织入的目标类。

在做spring项目时,如果代理对象是单例模式,选择cglib动态代理;如果是prototype模式,选择jdk动态代理。

一般不会用到Load Time Weaving代理。

但是,一些特殊情况jdk和cglib动态代理也有局限性,一些特殊情况只能选择Load Time Weaving代理。

jdk动态代理的局限:

因为jdk代理是 基于接口的动态代理技术,由于接口的方法都必然是public的,这就要求实现类的实现方法也必须是public的(不能是 protected、private等),同时不能使用static的修饰符。所以,可以实施jdk动态代理的方法只能使用public或public final修饰符的方法,其他方法不可能被动态代理,相应的也就不能实施AOP增强,换句话,即不能进行spring 增强了。

Cglib动态代理的局限:

基于Cglib字节码动态代理是通过扩展被增强类,动态创建其子类的方式进行AOP增强植入的。由于使用final、static、private修饰符的方法不能被子类覆盖,相应的,这些方法就无法实施AOP增强。

总结:jdk动态代理创建时效率比cglib高,但执行效率比cglib低。所以如果代理对象是单例模式,选择cglib动态代理;如果是prototype模式,选择jdk动态代理。

当遇到jdk和cglib代理局限性无法解决问题时,可以选择Load Time Weaving代理。

至于,aspectj 的Load Time Weaving技术的效率,没研究过,请大牛解惑。