Spring將事務代理工廠TransactionProxyFactoryBean或自動代理攔截器BeanNameAutoProxyCreator的proxyTargetClass屬性,設置爲true,則使用CGLIB代理,此屬性默認爲false,使用JDK動態代理。java
Spring AOP部分使用JDK動態代理或者CGLIB來爲目標對象建立代理。(建議儘可能使用JDK的動態代理)spring
若是被代理的目標對象實現了至少一個接口,則會使用JDK動態代理。全部該目標類型實現的接口都將被代理。若該目標對象沒有實現任何接口,則建立一個CGLIB代理。
若是你但願強制使用CGLIB代理,(例如:但願代理目標對象的全部方法,而不僅是實現接口的方法)那也能夠,可是須要考慮如下問題:
1.沒法通知(advise)Final 方法,由於他們不能被覆寫。
2.你須要將CGLIB 2二進制發行包放在classpath下面,與之相較JDK自己就提供了動態代理
3.強制使用CGLIB代理須要將 |aop:config| 的 proxy-target-class 屬性設爲true:性能
<aop:config proxy-target-class="true">
...
</aop:config>
當須要使用CGLIB代理和@AspectJ自動代理支持,請按照以下的方式設置 <aop:aspectj-autoproxy>的 proxy-target-class 屬性:spa
<aop:aspectj-autoproxy proxy-target-class="true"/>
而實際使用的過程當中纔會發現細節問題的差異,The devil is in the detail.代理
JDK動態代理:其代理對象必須是某個接口的實現,它是經過在運行期間建立一個接口的實現類來完成對目標對象的代理。
CGLIB代理:實現原理相似於JDK動態代理,只是它在運行期間生成的代理對象是針對目標類擴展的子類。CGLIB是高效的代碼生成包,底層是依靠ASM(開源的java字節碼編輯類庫)操做字節碼實現的,性能比JDK強。
Spring是依靠什麼來判斷採用哪一種代理策略來生成AOP代理呢?如下代碼就是Spring的判斷邏輯 對象
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代理。blog
若是當須要使用CGLIB代理和@AspectJ自動代理支持,請按照以下的方式設置<aop:aspectj-autoproxy> 的 proxy-target-class 屬性:
<aop:aspectj-autoproxy proxy-target-class="true"/>繼承
這樣使用CGLIB代理也就不會出現前面提到的ClassCastException問題了,也能夠在性能上有所提升,關鍵是對於代理對象是否繼承接口均可以統一使用CGLIB。接口