我相信spring aop中使用JDK动态代理与Cglib动态代理的区别这一问题在刚毕业的同学面试时都被问过。我们都会答:JDK动态代理的目标对象需要实现接口,Cglib动态代理的目标对象不需要实现接口。再牛逼一点的朋友可能会再答JDK动态代理通过反射来实现,Cglib动态代理通过对字节码的操作来实现的,动态代理可以用来做权限控制、事务、日志处理等作用。
再问下去我们就开始慌了因为我们知道动态代理可以用来做这些功能,但刚出来我们并没有真正用过动态代理,这些框架都已经封装好了,我们只要会增删查改就行了。
前几天我的同学面试被问到spring aop怎么设置使用JDK还是Cglib动态代理,他的答案是:不知道。
脑海中又出来了另一个问题:spring aop默认使用JDK还是Cglib动态代理?
那我们来探讨一下。使用springboot2.1搭建
我们都知道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,但并不是反射的效率要高于操作字节码。
操作字节码要效率远高于反射
即刻关注,掂过柱碌