1. 程式人生 > >Spring通過註解annotation方式注入Bean時,採用動態代理,那麼JDK代理和CGLIB代理區別?

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>