天天看點

IT忍者神龜之Java動态代理與CGLib代理

<br>public class UserDAOImpl{  

<br><br>    public void save() {  

<br>        // TODO Auto-generated method stub  

<br>        System.out.println("user saved");  

<br>    }  

<br>}  

<br>//相關配置,省略了一些不相關内容  

<br><bean id="userDAO" class="UserDAOImpl">  

<br><bean id="userDAOProxy"  class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">   

<br>    <property name="target">   

<br>        <ref local="userDAO" />   

<br>    </property>   

<br></bean>  

   測試代碼

        ApplicationContext ctx =  

<br>            new FileSystemXmlApplicationContext("applicationContext.xml");  

<br>        UserDAOImpl userDAOImpl =   

<br>            (UserDAOImpl)ctx.getBean("userDAOProxy");  

<br>        userDAOImpl.save();  

   上面這樣的情況下程式能夠正常執行,可是假設UserDAOImpl實作了一個接口,其它不變

public class UserDAOImpl implements UserDAO {  

<br>  

<br>    public void save() {  

 這樣的情況下,程式将不能正常執行,會抛出java.lang.ClassCastException異常

了解上面這樣的情況産生的原因須要了解Spring AOP的實作原理。

Spring 實作AOP是依賴JDK動态代理和CGLIB代理實作的。

下面是JDK動态代理和CGLIB代理簡介

    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動态代理政策動态的建立一個接口實作類(動态代理類)來代理目标對象。能夠通俗的了解這個動态代理類是目标對象的另外一個版本号。是以這兩者之間在強制轉換的時候會抛出j ava.lang.ClassCastException。而是以在預設情況下,假設目标對象沒有實作不論什麼接口,Spring會選擇CGLIB代理, 其生成的動态代理對象是目标類的子類。

     以上說的是預設情況下。也能夠手動配置一些選項使Spring採用CGLIB代理。

org.springframework.transaction.interceptor.TransactionProxyFactoryBean是org.springframework.aop.framework. ProxyConfig的子類,是以能夠參照ProxyConfig裡的一些設定例如以下所看到的,将optimize和proxyTargetClass随意一個設定為true都能夠強制Spring採用CGLIB代理。

//相關配置,省略了一些不相關内容  

<br>    <property name="optimize">   

<br>        <value>true</value>  

<br>    </property>  

<br>    <property name="proxyTargetClass">   

使用CGLIB代理也就不會出現前面提到的ClassCastException問題了,

也能夠在性能上有所提高,可是也有它的弊端,Spring doc原文解釋例如以下optimization will usually mean that advice changes won't take effect after a proxy has been created. For this reason, optimization  is disabled by default。

本文轉自mfrbuaa部落格園部落格,原文連結:http://www.cnblogs.com/mfrbuaa/p/5177571.html,如需轉載請自行聯系原作者