動態(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)代理。