spring 如何決定使用jdk動態代理和cglib(轉)

來源:互聯網
上載者:User

標籤: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(轉)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.