開發者學堂課程【Java 進階程式設計:動态代理設計模式】學習筆記,與課程緊密聯系,讓使用者快速學習知識。
課程位址:
https://developer.aliyun.com/learning/course/20/detail/394動态代理設計模式
内容簡介:
1.代理設計
2.代理方法
3.範例
通過靜态代理設計模式的缺陷可以發現,最好的做法是為所有功能一緻的業務操作接口提供有統一的代理處理操作,而這可以通過動态代理機制來實作,但是在動态代理機制裡面需要考慮到如下幾點問題:
1)不管是動态代理類還是靜态代理類都一定要接收真實業務實作子類對象。
動态代理機制,相當于有一個代理類,代理的是一堆業務接口。不管是靜态代理還是動态代理,在整個程式的處理過程之中,一定要保證它能夠接收所有的真實業務處理子類。
這裡通過 proxy 來接收:
2)由于動态代理類不再與某一個具體的接口進行捆綁,是以應該可以動态擷取類的接口資訊。
動态代理最終傳回給用戶端的是一個接口代理對象,但是這個代理類不會與任何接口産生聯系。
由于在每一個對象裡面都可以通過反射擷取接口,那麼在整個操作過程之中,可以直接使用
obj.getClass().getlnterfaces()
方法來擷取所有可能需要用到的接口的操作對象。
用戶端要想能夠正常執行處理,就必須準備出一個接口代理對象,而接口代理對象是通過反射接口獲得的,
如下圖:
當取得接口對象之後都會有一個專門的系統類,系統類會根據接口對象和傳過來的操作資訊,做出自己的接口代理對象。系統将根據類加載器建立一個所謂的系統對象,當用戶端通過代理對象進行操作的時候,本質上操作的就是接口。
在進行代理對象的建立和操作的過程之中,最重要的是 invocation Handler。Invocation Handler 實作的操作,就是在開發之中所做的代理方法控制。以上就是整個的代理設計模式的實作的結構,整個流程圖如下:
在進行動态代理實作的操作之中,首先需要關注的就是一個 Invocation Handler 接口,這個接口規定了代理方法的執行。
這個代碼由于要跨越到多個接口存在,是以方法名稱由程式自己定義。
把 invocation handler 打開,接口如下:
public interface InvocationHandler {
/**
* 代理方法調用,代理主題類裡面執行的方法最終都是此方法
* @param proxy要代理的對象
* @param method要執行的接口方法名稱
* @param args 傳遞的參數
* @return 某一個方法的傳回值
* @throws Throwable 方法調用時出現的錯誤繼續向上抛出
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
在進行動态代理設計的時候對于動态對象的建立是由JVM底層完成的,此時主要依靠的是 java.lang.reflect.Proxy 程式類,而這個程式類之中隻提供有一個核心方法:
代理對象:
public static Object newProxyInstance(ClassLoader loader,Class<?>[]interfaces,InvocationHandler h)
-ClassLoader loader
:擷取目前真實主題類的 ClassLoader;
- Class<?>[]interfaces
:代理是圍繞接口進行的,是以一定要擷取真實主題類的接口資訊;
- InvocationHandler h:
代理處理的方法。
在整個代理操作中,第一個操作 Invocation handler,第二個核心類 proxy。
在主類進行操作處理的時候,一定要接收的是業務的真實實作類,proxy 根 據真實業務類對象建立代理對象。
主類進行操作用的是 proxy 傳回的代理對象進行操作的,而這個代理對象最重要的特征是它的結構複合業務接口結構。
代理的對象不是直接去調用,它在調用的代理操作會找到 Invocation handler,方法 invoke()。
比如當調用對象的時候,業務接口中有個方法 fun():void,那麼代理對象發出的指令也是對象.fun()。但是當調用時,會找到 invoke,而後 invoke 去調用業務接口方法,業務接口方法就是業務的實作子類,以上就是整體的操作流程。
範例:實作動态代理機制
代碼執行結果如下:
******【執行方法】
public abstract void cn.mldn.demo.IMessage.send()
【消息代理】進行消息發送通道的連接配接
【發送消息】www.mldn.cn
【消息代理】關閉消息通道。
如果你認真觀察系統中提供的
Proxy.newProxyInstance()
方法,就會發現該方法會使用大量的底層機制來進行代理對象的動态建立,所有的代理類是複合所有相關功能需求的操作功能類,它不再代表具體的接口,這樣在處理的時候就必須依賴于類加載器與接口進行代理對象的僞造。