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