spring如何决定使⽤jdk动态代理和cglib(⽹易⾯试题)
Spring1.2:
将事务代理⼯⼚[TransactionProxyFactoryBean] 或⾃动代理[BeanNameAutoProxyCreator]
的proxyTargetClass属性,设置为true,则使⽤CGLIB代理,此属性默认为false,使⽤JDK动态代理.
以下引⽤ Spring Framework reference 2.0.5:
Spring2.0:
Spring AOP部分使⽤JDK动态代理或者CGLIB来为⽬标对象创建代理。(建议尽量使⽤JDK的动态代理)
如果被代理的⽬标对象实现了⾄少⼀个接⼝,则会使⽤JDK动态代理。所有该⽬标类型实现的接⼝都将被代理。若该⽬标对象没有实现任何接⼝,则创建⼀个CGLIB代理。
如果你希望强制使⽤CGLIB代理,(例如:希望代理⽬标对象的所有⽅法,⽽不只是实现⾃接⼝的⽅法)那也可以。但是需要考虑以下问题:
⽆法通知(advise)Final ⽅法,因为他们不能被覆写。
你需要将CGLIB 2⼆进制发⾏包放在classpath下⾯,与之相较JDK本⾝就提供了动态代理
强制使⽤CGLIB代理需要将 |aop:config| 的 proxy-target-class 属性设为true:
|aop:config proxy-target-class="true"|
...
|/aop:config|
当需要使⽤CGLIB代理和@AspectJ⾃动代理⽀持,请按照如下的⽅式设置 |aop:aspectj-autoproxy| 的 proxy-target-class 属性:
|aop:aspectj-autoproxy proxy-target-class="true"/|
⽽实际使⽤的过程中才会发现细节问题的差别,The devil is in the detail.JDK动态代理:其代理对象必须是某个接⼝的实现,它是通过在运⾏期间创建⼀个接⼝的实现类来完成对⽬标对象的代理。
CGLIB代理:实现原理类似于JDK动态代理,只是它在运⾏期间⽣成的代理对象是针对⽬标类扩展的
jdk怎么使用⼦类。CGLIB是⾼效的代码⽣成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能⽐JDK强。
Spring是依靠什么来判断采⽤哪种代理策略来⽣成AOP代理呢?以下代码就是Spring的判断逻辑
//org.springframework.aop.framework.DefaultAopProxyFactory
//参数AdvisedSupport 是Spring AOP配置相关类
public AopProxy createAopProxy(AdvisedSupport advisedSupport)
throws AopConfigException {
//在此判断使⽤JDK动态代理还是CGLIB代理
if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass()
|| hasNoUserSuppliedProxyInterfaces(advisedSupport)) {
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. "
+ "Add CGLIB to the class path or specify proxy interfaces.");
}
ateCglibProxy(advisedSupport);
} else {
return new JdkDynamicAopProxy(advisedSupport);
}
}
advisedSupport.isOptimize()与advisedSupport.isProxyTargetClass()默认返回都是false,所以在默认情况下⽬标对象有没有实现接⼝决定着Spring采取的策略,当然可以设置advisedSupport.isOptimize()或者advisedSupport.isProxyTargetClass()返回为true,这样⽆论⽬标对象有没有实现接⼝Spring都会选择使⽤CGLIB代理。
所以在默认情况下,如果⼀个⽬标对象如果实现了接⼝Spring则会选择JDK动态代理策略动态的创建⼀个接⼝实现类(动态代理类)来代理⽬标对象,可以通俗的理解这个动态代理类是⽬标对象的另外⼀个版本,所以这两者之间在强制转换的时候会抛出
java.lang.ClassCastException。⽽所以在默认情况下,如果⽬标对象没有实现任何接⼝,Spring会选择CGLIB代理,其⽣成的动态代理对象是⽬标类的⼦类。
上说的是默认情况下,也可以⼿动配置⼀些选项使Spring采⽤CGLIB代理。
ansaction.interceptor.TransactionProxyFactoryBean是org.springframework.aop.framework. ProxyConfig的⼦类,所以可以参照ProxyConfig⾥的⼀些设置如下所⽰,将optimize和proxyTargetClass任意⼀个设置为true都可以强制Spring采⽤CGLIB代理。
如果当需要使⽤CGLIB代理和@AspectJ⾃动代理⽀持,请按照如下的⽅式设置 |aop:aspectj-autoproxy| 的 proxy-target-class 属性:
|aop:aspectj-autoproxy proxy-target-class="true"/|
这样使⽤CGLIB代理也就不会出现前⾯提到的ClassCastException问题了,也可以在性能上有所提⾼,关键是对于代理对象是否继承接⼝可以统⼀使⽤。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论