我相信spring aop中使用JDK动态代理与Cglib动态代理的区别这一问题在刚毕业的同窗面试时都被问过。
咱们都会答:
JDK动态代理的目标对象须要实现接口,Cglib动态代理的目标对象不须要实现接口。
再牛逼一点的朋友可能会再答JDK动态代理经过反射来实现,Cglib动态代理经过对字节码的操做来实现的,动态代理能够用来作权限控制、事务、日志处理等做用。
再问下去咱们就开始慌了
由于咱们知道动态代理能够用来作这些功能,但刚出来咱们并无真正用过动态代理,这些框架都已经封装好了,咱们只要会增删查改就好了。
前几天个人同窗面试被问到spring aop怎么设置使用JDK仍是Cglib动态代理,他的答案是:不知道。
脑海中又出来了另外一个问题:spring aop默认使用JDK仍是Cglib动态代理?
那咱们来探讨一下。
咱们都知道JDK动态代理须要实现接口,那咱们建立一个实现接口和不实现接口的类来测试一下测试
不实现接口的类优化
实现接口的类
springboot用aspect实现aop须要的类,这里就不讲解如何使用的了代理
这个自定义注解类用于指定哪一个方法须要使用aop日志
使用springboot的test测试运行,直接运行,没有做其余的配置
打印结果,发现springboot的aop无论有没有实现接口,默认都是使用CGLIB动态代理
那么咱们如何设置aop使用的动态代理方式,咱们须要设置
spring.aop.proxy-target-class这个属性的值。
默认为true表示强制使用Cglib动态代理
如今设置成false
咱们看一下运行的结果
发现实现接口的类变成了com.sun.proxy,表示使用的是JDK的动态代理。
咱们回到以前的问题,spring aop怎么设置使用JDK仍是Cglib动态代理,答案就呼之欲出了。这里是以springboot2.0以后的版本为标准
pringboot2.0的aop,无论有没有实现接口,默认使用的都是Cglib动态代理,若是想使用JDK动态代理,须要在配置文件中设置
spring.aop.proxy-target-class=false
那么使用aop时实现了接口的类就会使用JDK动态代理,没有实现接口的类仍然使用的是Cglib动态代理。
下面简单记录一下JDK动态代理与Cglib动态代理的区别,其实不少博客都总结过,这里记录只为方便回顾
1.java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,经过修改其字节码生成子类来处理。
2.JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
为何JDK动态代理必需要实现接口?
由于java的单继承,动态生成的代理类已经继承了Proxy类,就不能再继承其余的类,要与代理类联系起来,只能实现接口
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
3.JDK动态代理与Cglib动态代理效率比较?
jdk1.7以前JDK动态代理的效率要低于Cglib,但jdk1.7以后,java作了优化JDK动态代理的效率要高于Cglib
虽而后来优化后JDK动态代理效率要高于Cglib,但并非反射的效率要高于操做字节码。
操做字节码要效率远高于反射