標籤:ring 通過 方法調用 lan 比較 turn invoke int 就是
我覺得要理解動態代理,首先要理解靜態代理,因為動態代理是為瞭解決靜態問題才出現,詳見上一篇靜態代理的總結,直接看圖
可以看出來,代理的實現就是這三方類,所以為瞭解決靜態代理的弊端,需要在啟動並執行時候動態組建代理程式類。
而在java中jdk提供了proxy類建立動態類,jdk中是這樣定義的
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class<?>[] { Foo.class }, handler);
先說明一下三個參數,第一個參數是被代理類的類載入器,第二個參數是被代理類的執行個體,最重要的是第三個參數,是一個InvocationHandler對象,最終我們要調用的方法就是要傳入這個handler對象,
這個handle對象裡面只有invoke方法
invoke(Object proxy, 方法 method, Object[] args)
處理代理執行個體上的方法調用並返回結果。 這是在jdk上的解釋,說白了,我們要做的商務邏輯就是寫在這裡,這個invoke裡面也有三個參數,其實我覺得proxy類裡面對這三個參數解釋的挺清楚的了,
通過其代理介面之一的代理執行個體上的方法調用將被指派到執行個體調用處理常式的invoke方法,代理執行個體, java.lang.reflect.Method被呼叫者法的java.lang.reflect.Method對象以及包含參數的類型Object Object的數組。 調用處理常式適當地處理編碼方法調用,並且返回的結果將作為方法在代理執行個體上調用的結果返回。
第一個參數proxy是我們動態建立的代理對象,就是上面的第一句話,代理執行個體!第二參數就是目標方法的位元組碼對象,就是被代理方法的方法組成的數組,如果你不懂什麼是位元組碼或者類載入器,你就直接當成方法數組就好了,最後一個參數代表是調用目標方法時參數。返回就是調用代理對象方法的返回返回就可以了
/** 介面* */public interface TargetInterface { public void method1(); public String method2(); public int method3(int x);}/** 被代理類* */public class Target implements TargetInterface{ @Override public void method1() { System.out.println("method1 running..."); } @Override public String method2() { System.out.println("method2 running..."); return "method2"; } @Override public int method3(int x) { return x; }}/** 測試動態代理* */public class ProxyTest { @Test public void test1(){ //獲得動態代理對象----在運行時 在記憶體中動態為Target建立一個虛擬代理對象 //objProxy是代理對象 根據參數確定到底是誰的代理對象 TargetInterface objProxy = (TargetInterface) Proxy.newProxyInstance( Target.class.getClassLoader(), //與目標對象相同的類載入器 new Class[]{TargetInterface.class}, new InvocationHandler() { //invoke 代表的是執行代理對象的方法 @Override //method:代表目標對象的方法位元組碼對象 //args:代表目標對象的響應的方法的參數 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("目標方法前的邏輯"); //執行目標對象的方法 Object invoke = method.invoke(new Target(), args); System.out.println("目標方法後的邏輯"); return invoke; } } ); objProxy.method1(); String method2 = objProxy.method2(); System.out.println(method2); } }這裡面很多東西我已經注釋了,比較難理解的可能是這一句
Object invoke = method.invoke(new Target(), args);
這句代碼如果你瞭解反射的話,應該可以看出來,這其實就是做了一個反射,第一個參數就是被代理類的執行個體,args就是方法的參數,這句話其實就是調用被代理對象的方法。也就是說在這個invoke裡面我們可以對對象進行增強,
最後我再總結一下,動態代理底層應該使用了反射的原理,根據傳進來的類的介面的位元組碼檔案(即new Class<?>[] { Foo.class }參數),動態建立一個代理類,當我們在調用這個代理類的方法的時候(即objProxy.method1();)
我們實際上調用了invoke方法,反射的使用了被代理類的方法。
java中的動態代理