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動態代理,只是它在運行期間生成的代理對象是針對目標類擴展的子類。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.
"
);
}
return
CglibProxyFactory.createCglibProxy(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代理。
org.springframework.transaction.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問題了,也可以在性能上有所提高,關鍵是對於代理對象是否繼承接口可以統一使用。