一文讀懂java動態(tài)代理

動態(tài)代理的好處

Java動態(tài)代理的優(yōu)勢是實現(xiàn)無侵入式的代碼擴展,也就是方法的增強;讓你可以在不用修改源碼的情況下,增強一些方法;在方法的前后你可以做你任何想做的事情(甚至不去執(zhí)行這個方法就可以)。此外,也可以減少代碼量,如果采用靜態(tài)代理,類的方法比較多的時候,得手寫大量代碼。

動態(tài)代理示例:

接口類:

public?interface?UserService {?

????public?abstract?void?add();

????public?abstract?void?update();

}

接口實現(xiàn)類:

public?class?UserServiceImpl?implements?UserService {?


?????public?void?add() {?

????????System.out.println("----- add -----");?

????}


????public?void?update(){

?????????System.out.println("----- update-----");?

????}

}

代理處理類MyInvocationHandler.java

import?java.lang.reflect.InvocationHandler;?

import?java.lang.reflect.Method;?

import?java.lang.reflect.Proxy;?


public?class?MyInvocationHandler?implements?InvocationHandler {?


????private?Object target;?


????public?MyInvocationHandler(Object target) {

?//注入目標對象,方便在invoke中調(diào)用目標對象的目標方法

????????super();?

????????this.target = target;?

????}?


????public?Object getProxy() {?

????????return?Proxy.newProxyInstance(Thread.currentThread()?

????????????????.getContextClassLoader(), target.getClass().getInterfaces(),?

????????????????this);?

//指定代理類生成時的加載器,要實現(xiàn)的接口,代理類的代理方法被調(diào)用時需要調(diào)用哪個對象的invoke方法。

????}?


????@Override?

????public?Object invoke(Object proxy, Method method, Object[] args)?

????????????throws?Throwable {?

//代理類的代理方法被調(diào)用時,會調(diào)用傳入的h對象的invoke方法。

????????System.out.println("----- before -----");?

????????Object result = method.invoke(target, args);?

//調(diào)用真正的目標類的目標方法。

????????System.out.println("----- after -----");?

????????return?result;?

????}?

}?

測試類:

public?class?DynamicProxyTest {?


????public?static?void?main(String[] args) {?

????????UserService userService =?new?UserServiceImpl();?

????????MyInvocationHandler invocationHandler =?new?MyInvocationHandler(?

????????????????userService);?


????????UserService proxy = (UserService) invocationHandler.getProxy();?

????????proxy.add();

????????proxy.update();

????}?

}?

輸出:

----- before -----

----- add -----

----- after -----

----- before -----

----- update -----

----- after -----

其基本過程如下: 1.定義目標類接口和目標類? 2.實現(xiàn)InvocationHandler接口,在構(gòu)造方法中注入目標類,實現(xiàn)獲取代理類的方法getProxy()?,該方法中調(diào)用Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(),?this);?傳入的類加載器用于加載生成的代理類的字節(jié)碼(ProxyGenerator.generateProxyClass()的方法是最終生成代理類的字節(jié)碼.),傳入的接口(可以為多個)用于規(guī)定生成的代理類需要代理的方法有哪些,傳入的this對象必須是InvocationHandler的實現(xiàn)類對象(稱為h對象),因為最終生成的代理對象的方法在被調(diào)用是全部是通過轉(zhuǎn)發(fā)給對象h的invoke方法來處理的,你可以在invoke方法中通過method.invoke(target, args);來調(diào)用目標類的方法,同時在調(diào)用之前或者之后加入自己的功能代碼。

//重點就是這里,代理類實現(xiàn)的接口方法

??public?final?void?sayHello(String paramString) {?

????try?{<br>??????//見上面構(gòu)造方法,this.h 就代表MyInvocationHandler類,所以執(zhí)行的就是我們代理實現(xiàn)類中的invoke方法。

??????this.h.invoke(this, m3,?new?Object[] { paramString });?

??????return;?

????}?

????catch?(Error|RuntimeException localError) {?

??????throw?localError;?

????}?

????catch?(Throwable localThrowable) {?

??????throw?new?UndeclaredThrowableException(localThrowable);?

????}?

??}?

我們可以把 InvocationHandler 看做一個中介類,中介類持有一個被代理的目標對象,在 invoke 方法中調(diào)用了目標對象的相應(yīng)方法,而生成的代理類中持有中介類,因此,當我們在調(diào)用代理類的方法的時候,調(diào)用被轉(zhuǎn)發(fā)到中介類h的 invoke 方法,再轉(zhuǎn)為對被目標對象的調(diào)用。

生成的代理類:$Proxy0 extends Proxy implements Person,我們看到代理類繼承了 Proxy 類,由于java中的單繼承,所以也就決定了生成的 java 動態(tài)代理類不能再繼承其它類,只能對接口進行代理,所以Java 的動態(tài)代理類無法實現(xiàn)直接針對 類的動態(tài)代理,只能通過接口間接實現(xiàn)對類的動態(tài)代理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容