設計模式之Jdk動態代理 設計模式之代理模式

什麼是動態代理呢?
就是在java的運行過程中,動態的生成的代理類。(爲了更熟悉的瞭解動態代理,你必須先熟悉代理模式,可點擊設計模式之代理模式 閱讀)
我們知道java屬於解釋型語言,是在運行過程中,尋找字節碼文件從而實現類加載的。
但是字節碼文件並不需要一定是硬盤中的class文件,也可以是來自網絡、數據庫或者是直接生成的數據流。因此這就給虛擬機動態的生成代理類提供了可能。
Java 1.3 正式引入,動態代理(Dynamic proxies)特性。
前一篇文章我們已經知道Proxy是代理模式的核心,而動態代理就是在運行期間由虛擬機根據需要,動態的生成出這樣一個代理類。
我們可以直接看java的實現方法:

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Proxy;
 3 
 4 public class DynamicProxyInvoker
 5 {
 6     public static void main(String[] args)
 7     {
 8         InvocationHandler proxyHandler = new SuperStarInvocationHandler("messi");
 9         ISuperStar superStarDynamicProxy = (ISuperStar) Proxy.newProxyInstance(ISuperStar.class.getClassLoader(), new Class<?>[]
10         { ISuperStar.class }, proxyHandler);
11         superStarDynamicProxy.signContract();
12         superStarDynamicProxy.negotiate();
13     }
14 }
 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 
 4 public class SuperStarInvocationHandler implements InvocationHandler
 5 {
 6     private String proxyName;
 7     ISuperStar superStar;
 8     
 9     public SuperStarInvocationHandler(String startName)
10     {
11         this.proxyName = startName + "'s proxy";
12         superStar = new SuperStar(startName);
13     }
14     
15     @Override
16     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
17     {
18         System.out.println(proxyName + " signContract");
19         Object object = method.invoke(superStar, args);
20         return object;
21     }
22     
23 }
 1 public interface ISuperStar
 2 {
 3     /**
 4      * 簽約
 5      */
 6     public void signContract();
 7     
 8     /**
 9      * 談判
10      */
11     public void negotiate();
12 }
 1 public class SuperStar implements ISuperStar
 2 {
 3     private String starName;
 4     public SuperStar(String starName)
 5     {
 6         this.starName=starName;
 7     }
 8     
 9     @Override
10     public void signContract()
11     {
12         System.out.println(starName+" signContract");
13         // to do sth
14         return;
15     }
16     
17     @Override
18     public void negotiate()
19     {
20         System.out.println(starName+" negotiate");
21         // to do sth
22         return;
23     }
24 }

superStarDynamicProxy是由系統自動生成的,一個實現了接口ISuperStar的類。這個類並不存在於具體的實現。同時由於系統也不知道我們具體需要在代理類中做哪些的操作。
因此需要我們自己提前安排好一個處理類SuperStarInvocationHandler。這個處理類中實現了代理類中是如何調用實現類中的方法的邏輯。
他們的調用關係圖是這樣的:


       我們可以看到動態代理的結構圖中,代理方並不會直接調用到被代理方,而是通過業務處理類來調用的。因此業務處理類需要保持一個被代理方的實例對象。(非強制)通過虛擬機主動生成動態代理類,我們可以發現,調用方和被調用方在代碼實現階段其實是斷層的。並不存在依次的直接調用關係。因此耦合的概念會更淺。同時由於不再需要爲像靜態代理那樣爲每個類都實現一個代理類,因此以切面的形式加入代理層成爲可能。這個我會在後續的文章中介紹。

       ps :有興趣的同學可以在main方法中手動的將動態代理生成的代理方superStarDynamicProxy的字節碼導入到一個.class文件中,然後反編譯該文件。你就會發現,這個類其實就是被代理方所實現接口的一個適配類。其中的所有方法的實現都是調用業務處理類SuperStarInvocationHandler,再由業務處理類通過反射動態的調用到SuperStar類的。


動態代理的不足

1、早期由於jdk反射的性能有限,因此jdk的動態代理方式在性能上並不是很優越,但是隨着jdk對於反射性能的優化,此處的性能損耗已經越來越小。
2、從構建動態代理類的源碼(有興趣的同學也可以按照前文的形式反編譯),或者是手動添加一個Instance Proxy的形式。
我們可以發現,代理類其實是繼承自Proxy的同時實現了接口。因此動態代理只能用來解決接口動態代理的場景,因爲java是不允許集成自多個類的。此問題可以使用CGLIB來解決,有興趣的同學可以自己看下,這個我會在後邊的文章中介紹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章