動(dòng)態(tài)代理的好處
Java動(dòng)態(tài)代理的優(yōu)勢(shì)是實(shí)現(xiàn)無(wú)侵入式的代碼擴(kuò)展哮翘,也就是方法的增強(qiáng);讓你可以在不用修改源碼的情況下仔涩,增強(qiáng)一些方法忍坷;在方法的前后你可以做你任何想做的事情(甚至不去執(zhí)行這個(gè)方法就可以)。此外熔脂,也可以減少代碼量,如果采用靜態(tài)代理柑肴,類(lèi)的方法比較多的時(shí)候霞揉,得手寫(xiě)大量代碼。
動(dòng)態(tài)代理示例:
接口類(lèi):
public?interface?UserService {?
????public?abstract?void?add();
????public?abstract?void?update();
}
接口實(shí)現(xiàn)類(lèi):
public?class?UserServiceImpl?implements?UserService {?
?????public?void?add() {?
????????System.out.println("----- add -----");?
????}
????public?void?update(){
?????????System.out.println("----- update-----");?
????}
}
代理處理類(lèi)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) {
?//注入目標(biāo)對(duì)象晰骑,方便在invoke中調(diào)用目標(biāo)對(duì)象的目標(biāo)方法
????????super();?
????????this.target = target;?
????}?
????public?Object getProxy() {?
????????return?Proxy.newProxyInstance(Thread.currentThread()?
????????????????.getContextClassLoader(), target.getClass().getInterfaces(),?
????????????????this);?
//指定代理類(lèi)生成時(shí)的加載器适秩,要實(shí)現(xiàn)的接口,代理類(lèi)的代理方法被調(diào)用時(shí)需要調(diào)用哪個(gè)對(duì)象的invoke方法硕舆。
????}?
????@Override?
????public?Object invoke(Object proxy, Method method, Object[] args)?
????????????throws?Throwable {?
//代理類(lèi)的代理方法被調(diào)用時(shí)秽荞,會(huì)調(diào)用傳入的h對(duì)象的invoke方法。
????????System.out.println("----- before -----");?
????????Object result = method.invoke(target, args);?
//調(diào)用真正的目標(biāo)類(lèi)的目標(biāo)方法抚官。
????????System.out.println("----- after -----");?
????????return?result;?
????}?
}?
測(cè)試類(lèi):
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 -----
其基本過(guò)程如下: 1.定義目標(biāo)類(lèi)接口和目標(biāo)類(lèi)? 2.實(shí)現(xiàn)InvocationHandler接口扬跋,在構(gòu)造方法中注入目標(biāo)類(lèi),實(shí)現(xiàn)獲取代理類(lèi)的方法getProxy()?凌节,該方法中調(diào)用Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(),?this);?傳入的類(lèi)加載器用于加載生成的代理類(lèi)的字節(jié)碼(ProxyGenerator.generateProxyClass()的方法是最終生成代理類(lèi)的字節(jié)碼.)钦听,傳入的接口(可以為多個(gè))用于規(guī)定生成的代理類(lèi)需要代理的方法有哪些洒试,傳入的this對(duì)象必須是InvocationHandler的實(shí)現(xiàn)類(lèi)對(duì)象(稱(chēng)為h對(duì)象),因?yàn)樽罱K生成的代理對(duì)象的方法在被調(diào)用是全部是通過(guò)轉(zhuǎn)發(fā)給對(duì)象h的invoke方法來(lái)處理的朴上,你可以在invoke方法中通過(guò)method.invoke(target, args);來(lái)調(diào)用目標(biāo)類(lèi)的方法垒棋,同時(shí)在調(diào)用之前或者之后加入自己的功能代碼。
//重點(diǎn)就是這里痪宰,代理類(lèi)實(shí)現(xiàn)的接口方法
??public?final?void?sayHello(String paramString) {?
????try?{<br>??????//見(jiàn)上面構(gòu)造方法叼架,this.h 就代表MyInvocationHandler類(lèi),所以執(zhí)行的就是我們代理實(shí)現(xiàn)類(lèi)中的invoke方法。
??????this.h.invoke(this, m3,?new?Object[] { paramString });?
??????return;?
????}?
????catch?(Error|RuntimeException localError) {?
??????throw?localError;?
????}?
????catch?(Throwable localThrowable) {?
??????throw?new?UndeclaredThrowableException(localThrowable);?
????}?
??}?
我們可以把 InvocationHandler 看做一個(gè)中介類(lèi)衣撬,中介類(lèi)持有一個(gè)被代理的目標(biāo)對(duì)象碉碉,在 invoke 方法中調(diào)用了目標(biāo)對(duì)象的相應(yīng)方法,而生成的代理類(lèi)中持有中介類(lèi)淮韭,因此垢粮,當(dāng)我們?cè)谡{(diào)用代理類(lèi)的方法的時(shí)候,調(diào)用被轉(zhuǎn)發(fā)到中介類(lèi)h的 invoke 方法靠粪,再轉(zhuǎn)為對(duì)被目標(biāo)對(duì)象的調(diào)用蜡吧。
生成的代理類(lèi):$Proxy0 extends Proxy implements Person,我們看到代理類(lèi)繼承了 Proxy 類(lèi)占键,由于java中的單繼承昔善,所以也就決定了生成的 java 動(dòng)態(tài)代理類(lèi)不能再繼承其它類(lèi),只能對(duì)接口進(jìn)行代理畔乙,所以Java 的動(dòng)態(tài)代理類(lèi)無(wú)法實(shí)現(xiàn)直接針對(duì) 類(lèi)的動(dòng)態(tài)代理君仆,只能通過(guò)接口間接實(shí)現(xiàn)對(duì)類(lèi)的動(dòng)態(tài)代理。