什麼是動態代理呢?就是在java的運行過程中,動態的生成的代理類。(為了更熟悉的瞭解動態代理,你必須先熟悉代理模式,可點擊設計模式之代理模式 閱讀)我們知道java屬於解釋型語言,是在運行過程中,尋找位元組碼文件從而實現類載入的。但是位元組碼文件並不需要一定是硬碟中的class文件,也可以是來自網路、數 ...
什麼是動態代理呢?
就是在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來解決,有興趣的同學可以自己看下,這個我會在後邊的文章中介紹。