Spring通過註解annotation方式注入Bean時,採用動態代理,那麼JDK代理和CGLIB代理區別?
切面程式設計是Spring中非常重要的一個模組,切面程式設計的實現原理是動態代理,那麼動態代理又有兩種實現方式:一種方法是直接實現JDK中的InvocationHandler
介面,另一種方法是繼承CGLIB。
首先如果不是很清楚兩者的區別的話,記住一般情況下InvocationHandler
要比CGLIB要好就行了。
(1)如果目標物件至少實現了一個介面,那麼就用JDK動態代理,所有由目標物件實現的介面將全部都被代理。
(2)如果目標物件沒有實現任何介面,就是個類,那麼就用CGLIB代理。
如今Spring的動態代理已經預設時JDK動態代理,實現類的單元測試中簡單方式就是通過加資源註解明確實現類,再通過注入實現類介面實現Bean的依賴注入。
@AutoWired
@Resource(name="areaServiceImpl")
private AdminService adminServiceImpl;
}
但是如果非要使用CGLIB的話,那麼CGLIB可能有下面的問題:
-
剛才提到了,
InvocationHandler
是實現的介面,而CGLIB則是繼承的父類,那麼由於繼承的限制,如果父類中有final的成員,那麼是繼承不到的。 -
還有從Spring 3.2以後不再將CGLIB放在專案的classpath下,而是將CGLIB類打包放在spring-core下面的org.springframework中。這個就意味著基於CGLIB的動態代理與JDK的動態代理在支援“just works”就一樣了。
-
在Spring 4.0中,因為CGLIB代理例項是通過Objenesis建立的,所以代理物件的構造器不再有兩次呼叫。
(1)想要強制使用CGLIB,spring配置檔案中<aop:config>
下面的proxy-target-class
屬性為true
:
<aop:config proxy-target-class="true">
<!-- other beans defined here... -->
</aop:config>
(2)對@AspectJ強制使用CGLIB的話,spring配置檔案中<aop:aspectj-autoproxy>
proxy-target-class
屬性為true
:
新增CGLIB庫,SPRING_HOME/cglib/*.jar
在spring配置檔案中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
maven依賴
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<!--<version>2.2.2</version>-->
</dependency>