通過JDK實現動態代理,有代理需求的類(這裡稱之為實作類別)必須要實現介面。動態代理可以將邏輯切片,通過代理類(proxy)代實作類別實現邏輯,期間還可以進行一些其他的操作。JDK的動態代理主要涉及到java.lang.reflect包中的兩個類:Proxy和InvocationHandler。其中 InvocationHandler是一個介面,可以通過實現該介面定義橫切邏輯,在並通過反射機制調用目標類的代碼,動態將橫切邏輯和商務邏輯編織在一 起。關於動態這塊兒一直比較迷惑,傻傻分不清楚,今天又有了新的理解,下面通過一個簡單的例子來說明:
先敘述下事務邏輯:一個人(people對象)通過交通工具(Transportation處理類)去了外國(日本、英國)
1、將去英國和日本這兩件事當做兩個介面,由人來實現
package com.impetention.lei;public interface Japan{ public void goJapan();}--------------------------------------------package com.impetention.lei;public interface England{ public void goEngland();}-------------------------------------------------package com.impetention.lei;//實作類別public class People implements England,Japan{ @Override public void goEngland() { // TODO Auto-generated method stub System.out.println("I am in England !"); } @Override public void goJapan() { // TODO Auto-generated method stub System.out.println("I am in Japan !"); }}
2、現在介紹一下InvocationHandler ,它是代理類的調用處理常式 實現的介面。每個代理類都具有一個關聯的調用處理常式,在執行個體化代理類時會添加進去一個InvocationHandler類型的處理類(完成事務邏輯的主題)。
如:
package com.invocation;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import com.impetention.lei.People;//人通過交通工具(代理)去國外public class Transportation implements InvocationHandler{ //一個叫zhang的人 private Object zhang = null; public Transportation(Object zhang) { this.zhang = zhang; } @Override public Object invoke(Object proxy, Method method, Object[] args) { // TODO Auto-generated method stub System.out.println("可以執行一些其他方法....."); //記錄執行結果 Object result = null; zhang = new People(); //在zhang對象上執行method方法,並將結果返回 try { result = method.invoke(zhang, args); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("---------------------"); return result; }}
注意裡面紅色的proxy,它就是代理類執行個體。這裡有必要對invoke(Object proxy, Method method, Object[] args) 做出一些解釋,動態代理類proxy0調用goEngland()方法時會調用它自己的goEngland()方法, 而它自己的goEngland()方法裡面調用的是其綁定對象InvocationHandler對象的invoke()方法, 也就是Transportation的invoke方法。invoke(Object proxy, Method m, Object[] args)種的proxy實際上就是動態代理類proxy, 如果你將其強轉成England然後調用它的goEngland()方法,它又會觸發代理類的goEngland()方法,代理類又調用InvocationHandler(transportation)的invoke()方法,這樣就會死迴圈。
3、代理實現:
package com.main;import java.lang.reflect.Proxy;import com.impetention.lei.England;import com.impetention.lei.Japan;import com.impetention.lei.People;import com.invocation.Transportation;public class Peopletest{ public static void main(String[] args) { //準備用動態代理實現,一個叫li的人通過交通工具到了英國 England li = new People(); //執行個體化transportation對象 Transportation t1 = new Transportation(li); //通過li.getClass().getClassLoader()實作類別的類載入器和li.getClass().getInterfaces()實作類別實現的所有介面作為參數調用
//Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)的方法返回代理類的java.lang.Class對象獲得了一個proxy代理類,
//必須給它一個InvocationHandler參數,也就是我們自己實現的用來在代理類方法執行前後做額外工作的類transpotation。將代理類強轉成England類型
England proxy = (England) Proxy.newProxyInstance(li.getClass().getClassLoader(), li.getClass().getInterfaces(), t1); proxy.goEngland(); //準備用動態代理實現,一個叫li的人通過交通工具到了英國 Japan lei = new People(); //執行個體化transportation對象 Transportation t2 = new Transportation(lei); //通過li.getClass().getClassLoader()和li.getClass().getInterfaces()獲得了一個 //(java.lang.class)proxy代理類,並以tt為參數對其進行執行個體化,強轉成people類型 Japan proxy1 = (Japan) Proxy.newProxyInstance(li.getClass().getClassLoader(), li.getClass().getInterfaces(), t2); proxy1.goJapan(); }}
小結:過程是這樣的,people執行goEngland()方法不直接執行,而是通過代理類proxy,proxy執行它自己的goEngland(),會觸發Transportation調用invoke(),然後
method.invoke(zhang, args);zhang會調用它的method,即goEngland(),最後將結果返回。