Java反射02——動態代理
本文不涉及靜態代理,只涉及動態代理,本人見過將動態代理講的比較好的文章在底部,有興趣的讀者可以移步。
老步驟:
1.什麼是動態代理?
通俗的講,動態代理就是建立一個類的代理物件,當需要訪問這個類的某些方法時,可以通過呼叫代理物件的同名方法,而真正實現的確實這個類的方法。
2.為什麼需要動態代理?
a.設計模式中有一個設計原則是
開閉原則
,是說對修改關閉對擴充套件開放,我們在工作中有時會接手很多前人的程式碼,裡面程式碼邏輯讓人摸不著頭腦(sometimes the code is really like shit),這時就很難去下手修改程式碼,那麼這時我們就可以通過代理對類進行增強。
b.我們在使用RPC框架的時候,框架本身並不能提前知道各個業務方要呼叫哪些介面的哪些方法 。那麼這個時候,就可用通過動態代理的方式來建立一箇中間人給客戶端使用,也方便框架進行搭建邏輯,某種程度上也是客戶端程式碼和框架鬆耦合的一種表現。
c.Spring的AOP機制就是採用動態代理的機制來實現切面程式設計。[1]
3.怎麼實現動態代理?
想要實現動態代理,需要解決兩個問題
(1)如何根據被載入到記憶體中的被代理類,動態地建立代理類及其物件;
(2)當通過代理類的物件呼叫方法時,如何動態的呼叫被代理類中的同名方法;
其實直接以例項來說明是最好的,下面以人和超人為例來講解:
(1)先建立一個介面,裡面有兩個抽象方法
interface Human {
String eat(String food);
String word();
}
(2)某個類實現這個介面
class SuperMan implements Human{ @Override public String eat(String food) { return "超人最愛吃:" + food; } @Override public String word() { return "超人專門打怪獸"; } }
(3)建立一個專門生成代理類工廠
PS:學習動態代理之前一定要理解Java反射機制,不然很多地方沒法弄懂
class HumanProxyFactory { /** * 傳入被代理類,返回一個代理類物件 * @param obj * @return */ public static Object createProxy(Object obj) { MyInvocationHandler myInvocationHandler = new MyInvocationHandler(); myInvocationHandler.bind(obj); Object proxyInstance = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), myInvocationHandler); return proxyInstance; } }
上面最關鍵的行在於createProxy
方法的第四行,也就是如何生成一個代理類的物件(ProxyInstance),這裡使用了Java API自帶的一個類java.lang.reflect.Proxy
,有興趣的同學的可以直接看JDK的原始碼,本人也沒看過。Proxy類中存在一個專門建立代理類的函式newProxyInstance
,這裡面有三個引數,分別是被代理類的類載入器,被代理類實現的介面,以及一個實現了InvocationHandler
介面的物件,前兩個引數只要掌握了反射就能理解,重點在於第三個引數,所以下面需要自己寫一個類來實現InvocationHandler
介面。
(4)實現InvocationHandler
介面
/**
* 自己實現一個InvocationHandler介面,當代理類呼叫自己的方法時,實現的卻是被代理類的方法
*/
class MyInvocationHandler implements InvocationHandler {
Object obj;
public void bind(Object obj) {
this.obj = obj;
}
/**
* 傳入的是代理類物件,代理類物件的方法,以及該方法中的引數陣列
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/* 這裡的返回值,實際上是被代理類呼叫此方法的返回值,可以為null */
Object o = method.invoke(obj, args);
return o;
}
}
(5)在測試類中檢驗結果
public class ProxyTest {
public static void main(String[] args) {
Human proxy = (Human) HumanProxyFactory.createProxy(new SuperMan());
String s = proxy.eat("牛排");
System.out.println(s);
}
}
結果如下:
以上就是動態代理的基本原理