標籤:mil ann conf proxy 不能 自動 lib org 返回
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是依靠什麼來判斷採用哪種Proxy 原則來產生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動態Proxy 原則動態建立一個介面實作類別(動態代理類)來代理目標對象,可以通俗的理解這個動態代理類是目標對象的另外一個版本,所以這兩者之間在強制轉換的時候會拋出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問題了,也可以在效能上有所提高,關鍵是對於代理對象是否繼承介面可以統一使用。
spring 如何決定使用jdk動態代理和cglib(轉)