摘要:動態代理有多種不同的用途,例如,數據庫連接和事務管理用于單元測試的動態模擬對象其他類似的方法攔截。調用序列和下面的流程類似單元測試動態對象模擬利用動態代理實現單元測試的動態存根代理和代理。框架把包裝成動態代理。
使用反射可以在運行時動態實現接口。這可以使用類java.lang.reflect.Proxy。這個類的名稱是我將這些動態接口實現稱之為動態代理的原因。動態代理有多種不同的用途,例如,數據庫連接和事務管理、用于單元測試的動態模擬對象、其他類似AOP的方法攔截。
創建代理可以使用Proxy.newProxyInstance() 方法創建動態代理。newProxyInstance() 方法有3個參數:
"load"動態代理類的ClassLoader
需要實現的接口數組
接收所有方法轉發的InvocationHandler
示例如下:
InvocationHandler handler = new MyInvocationHandler(); MyInterface proxy = (MyInterface) Proxy.newProxyInstance( MyInterface.class.getClassLoader(), new Class[] { MyInterface.class }, handler);
運行代碼后,變量proxy包含一個MyInterface接口的動態實現。所有對代理對象的調用將被轉發到InvocationHandler接口的實現handler。InvocationHandler會在下一節介紹。
調用處理程序前文已經提到,必須傳一個InvocationHandler實現給Proxy.newProxyInstance()方法。所有動態代理調用都會傳給InvocationHandler實現。InvocationHandler接口代碼如下:
public interface InvocationHandler{ Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
示例實現如下:
public class MyInvocationHandler implements InvocationHandler{ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //do something "dynamic" } }
傳給invoke()方法的proxy參數是實現了對應接口的動態代理對象。通常情況下,你不需要這個對象。
傳給invoke()方法的Method對象代表調用動態代理實現的接口的方法。從Method對象可以獲得方法名稱、參數類型、返回值類型等。Methods 節有關于方法更詳細的描述。
Object[] args數組包含動態代理對象被調用的方法需要使用的參數。注意:基本類型(int、lang等)在動態代理中需要使用它們的包裝類型(Integer、Long等)。
已知動態代理至少用于以下目的:
數據庫連接和事務管理
用于單元測試的動態對象模擬
適配DI容器以自定義工廠接口
類AOP的方法攔截
數據庫連接與事務管理Spring框架有一個事務代理,可以開啟、提交/回滾事務。它是如何工作的,在文章Advanced Connection and Transaction Demarcation and Propagation中有詳細講解,所以這里只做簡要介紹。調用序列和下面的流程類似:
web controller --> proxy.execute(...); proxy --> connection.setAutoCommit(false); proxy --> realAction.execute(); realAction does database work proxy --> connection.commit();單元測試動態對象模擬
Butterfly Testing Tools 利用動態代理實現單元測試的動態存根、代理和代理。當使用類B(真實接口)測試類A,可以傳一個B的模擬實現給A以代替真實的B。所有的對B的方法調用都會被記錄,也可以去設置B模擬對象的返回值。
此外,Butterfly Testing Tools允許您包裝真實B為模擬B,所以對模擬B方法的調用都會被記錄,并且可以轉發到真實B。所以,這可以用來檢測調用真實B的方法。例如,如果測試一個Dao,你可以包裝數據庫連接為一個模擬對象。Dao是不知道區別的,且Dao可以按常用方法讀寫數據,這是因為模擬對象轉發給了數據庫連接。但是,現在你也通過模擬對象檢查Dao連接的屬性,例如如果調用了connection.close()(或者沒有調用),如果你期望的話。這通常不可能從DAO的返回值來確定。
依賴注入容器Butterfly Container有一個非常強大的特性,它允許你把整個容器注入到它創建的bean中。但是,你可能不希望在容器接口上有依賴,容器能自動適配你自定義的工廠接口。你只需要接口,不需要實現。因此,工廠接口和你的類可能像這樣:
public interface IMyFactory { Bean bean1(); Person person(); ... }
public class MyAction{ protected IMyFactory myFactory= null; public MyAction(IMyFactory factory){ this.myFactory = factory; } public void execute(){ Bean bean = this.myFactory.bean(); Person person = this.myFactory.person(); } }
當MyAction類調用容器通過構造函數注入的IMyFactory實例的方法時,方法調用被轉化為調用IContainer.instance()的方法,這是從容器的實例獲取的方法。因此,一個對象可以把Butterfly Container作為一個運行時工廠使用,而不僅僅是在創建時注入。并且,這對Butterfly Container 接口沒有特殊依賴。
類AOP的方法攔截Spring框架可以攔截所有對bean的方法調用,假如bean實現了某些接口。Spring框架把bean包裝成動態代理。所有bean調用都被動態代理截獲。代理在把調用請求委派給bean之前或之后可以決定去調用其他對象的其他方法。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71693.html
摘要:靜態方法生成動態代理類同樣需要通過類裝載器來進行裝載才能使用,它與普通類的唯一區別就是其字節碼是由在運行時動態生成的而非預存在于任何一個文件中。 代理:設計模式 代理是一種常用的設計模式,其目的就是為其他對象提供一個代理以控制對某個對象的訪問。代理類負責為委托類預處理消息,過濾消息并轉發消息,以及進行消息被委托類執行后的后續處理。showImg(https://segmentfault...
摘要:反射使用類對象提供的基本元數據,能從類對象中找出方法或字段的名稱,然后獲取表示方法或字段的對象。常見的反射手段有反射和反射。以之前的反射為例其中指定了方法的返回類型,其實不止如此。 Java反射機制主要提供了以下功能: 在運行時判斷任意一個對象所屬的類 在運行時構造任意一個類的對象 在運行時判斷任意一個類所具有的成員變量和方法 在運行時調用任意一個對象的方法 生成動態代理 很多框架...
摘要:相比硬編碼,反射要復雜的多,但其給我們帶來了更大的靈活性。實際上構造函數也是類的靜態方法,因此使用關鍵字創建類的新對象也會被當做對類的靜態引用,從而觸發類加載器對類的加載。基礎基礎主要是為反射提供通用特性的接口或基類。 1. Java類型系統 獲取Java類型系統,主要有兩個方式:一種是傳統的RTTI(Run-Time Type Identification),它假定我們在編譯時已經知...
摘要:接口與類型信息關鍵字的一種重要目標就是允許程序員隔離構件,進而降低耦合性。如果你編寫接口,那么就可以實現這一目標,但是通過類型信息,這種耦合性還是會傳播出去接口并非是對解耦的一種無懈可擊的保障。 點擊進入我的博客 運行時類型信息使得你可以在運行時發現和使用類型信息,主要有兩種方式: 傳統的RTTI,它假定我們在編譯時已經知道了所有的類型; 反射機制,它允許我們在運行時發現和使用類的...
閱讀 2650·2023-04-26 00:42
閱讀 2799·2021-09-24 10:34
閱讀 3810·2021-09-24 09:48
閱讀 4145·2021-09-03 10:28
閱讀 2576·2019-08-30 15:56
閱讀 2771·2019-08-30 15:55
閱讀 3254·2019-08-29 12:46
閱讀 2244·2019-08-28 17:52