在上一章我們看到了,新增的三種類都能實現對原始功能類進行添加功能的事務處理,這三種類就是一個代理。
但是這種代理是寫死的,怎樣實現對任意接口添加自定義的代理呢?
我們先來看一下之前的代理實現:
1 public class Impeat { 2 private InterfaceDo todo; 3 public Impeat(InterfaceDo todo) { 4 super(); 5 this.todo = todo; 6 } 7 public void dothings() { 8 todo.dosomething(); 9 System.out.println("我要吃飯了啊--------"); 10 } 11 }
因為這里我們的代理不需要再被其他代理引用,所以就不需要實現InterfaceDo接口,自然內部方法也是可以自定義,沒有必要
遵循InterfaceDo的方法定義,為了避免混淆,我們將其改為了dothings(),由於代理類都是這樣的一個書寫模式:定義成員變量、
構造函數為成員變量賦值為代理對象、自定義方法實現對代理對象方法的調用。我們索性定義一個接口,以后所有的代理類都按
照統一模式來寫,在JDK中就定義了這樣的一個接口InvocationHandler,我們的代理類都實現這個接口,遵循它的書寫方式,
下面我們再來看看代理類里面的元素:
InterfaceDo:需要代理對象的實現接口;
todo:需要代理的對象;
紅字:為代理對象添加的功能實現;
todo.dosomething():代理對象的原始功能。
既然要實現動態代理,那么這個代理實現的部分源碼,就不能寫死了(被代理對象的接口、被代理的對象以及被代理對象內部的
方法),接口我們可以自定義,被代理對象我們可以new出來,但是被代理對象內部的方法是不確定的,A代理對象可能是A方法,
B代理對象可能是B方法,C代理對象可能是C方法。
所以,我們要動態獲取代理對象的內部方法就得通過反射來獲得。
被代理對象的方法怎么獲得呢?由於被代理對象是實現了接口的,被代理對象的內部方法必定也是重寫自接口的定義方法的。那么
我們就可以從接口入手,獲取接口的方法定義。
來看看JDK的實現:
public class Handlerimp implements InvocationHandler { private Object obj; public Handlerimp(Object obj) { super(); this.obj = obj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("-----我要實現新的功能-----"); Object returnValue = method.invoke(obj, args); return returnValue; } }
是不是很眼熟,對,這個和我們之前的靜態代理實現模式一樣。只不過底層已經用反射幫我們獲得了被代理對象obj的方法method
以及方法的參數數組,然后通過被代理對象、方法、參數三者來執行被代理對象的方法-------method.invoke(proxy,args)。
接下來,我們實例化一個該代理類的實例:
public class Testperson { public static void main(String[] args) { InterfaceDo a = new Persontodo(); Handlerimp handler =new Handlerimp(a); ClassLoader loader = a.getClass().getClassLoader(); Class[] interfaces = a.getClass().getInterfaces(); InterfaceDo subject = (InterfaceDo) Proxy.newProxyInstance(loader, interfaces, handler); subject.dosomething(); subject.dothing(); } }
我們可以看到,JDK中通過Proxy類的靜態方法newProxyInstance()獲得代理類實例;
該方法實現了對被代理對象所有方法的遍歷,因此實現了對被代理對象所有方法的功能添加。
之后,我們就可以調用代理類的方法了。