代理的概念:為某個對象提供一個代理,以控制對這個對象的訪問。 代理類和委托類有共同的父類或父接口,這樣在任何使用委托類對象的地方都可以用代理對象替代。代理類負責請求的預處理、過濾、將請求分派給委托類處理、以及委托類執行完請求后的后續處理。

抽象對象角色:就是代理類和委托類共同的接口,聲明了目標對象和代理對象的共同接口,這樣一來在任何可以使用目標對象的地方都可以使用代理對象。 目標對象角色:就是委托類,定義了代理對象所代表的目標對象。 代理對象角色:就是代理類,代理對象內部含有目標對象的引用,從而可以在任何時候操作目標對象;代理對象提供一個與目標對象相同的接口,以便可以在任何時候替代目標對象。代理對象通常在客戶端調用傳遞給目標對象之前或之后,執行某個操作,而不是單純地將調用傳遞給目標對象。 靜態代理 代理類在程序運行前已經存在的代理方式稱為靜態代理。 /** * 定義Demo接口 */ public interface Demo { public void save(); } /** * DemoImpl實現Demo接口並覆寫save()方法 * 真實主題,執行具體業務 */ public class DemoImpl implements Demo { public void save() { System.out.println("調用save()方法"); } } /** * DemoImplProxy 也實現了Demo接口,並覆寫了save()方法,增加了自己的業務 * 代理主題,負責其他業務的處理 */ public class DemoImplProxy implements Demo { Demo demoImpl = new DemoImpl(); public void save() { System.out.println("開始記錄日志"); demoImpl.save(); System.out.println("開始結束日志"); } } 靜態代理有一個缺點,每個代理類只能為一個接口服務,這樣程序開發中必然會產生許多的代理類。 動態代理 代理類在程序運行前不存在、運行時由程序動態生成的代理方式稱為動態代理。 實現動態代理包括三步: (1). 新建代理類和委托類共同的接口以及委托類; (2). 實現InvocationHandler接口,這是負責連接代理類和委托類的中間類必須實現的接口; (3). 通過Proxy類新建代理類對象。 第一步:新建代理類和委托類共同的接口以及委托類 public interface Operate { public void operateMethod1(); public void operateMethod2(); public void operateMethod3(); } public class OperateImpl implements Operate { @Override public void operateMethod1() { System.out.println("Invoke operateMethod1"); sleep(110); } @Override public void operateMethod2() { System.out.println("Invoke operateMethod2"); sleep(120); } @Override public void operateMethod3() { System.out.println("Invoke operateMethod3"); sleep(130); } private static void sleep(long millSeconds) { try { Thread.sleep(millSeconds); } catch (InterruptedException e) { e.printStackTrace(); } } } 第二步:實現InvocationHandler接口 java.lang.reflect.InvocationHandler接口的定義如下: /** * *Object proxy:被代理的對象 *Method method:要調用的方法 *Object[] args:方法調用時所需要參數 */ public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } 實現 InvocationHandler 接口 public class TimingInvocationHandler implements InvocationHandler { private Object target; public TimingInvocationHandler() {} public TimingInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start = System.currentTimeMillis(); Object obj = method.invoke(target, args); System.out.println(method.getName() + " cost time is:" + (System.currentTimeMillis() - start)); return obj; } } 第三步:通過Proxy類新建代理類對象 java.lang.reflect.Proxy類的定義如下: /** *CLassLoader loader:類的加載器 *Class<?> interfaces:得到全部的接口 *InvocationHandler h:得到InvocationHandler接口的子類的實例 */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException public class Main { public static void main(String[] args) { // create proxy instance TimingInvocationHandler timingInvocationHandler = new TimingInvocationHandler(new OperateImpl()); Operate operate = (Operate)(Proxy.newProxyInstance(Operate.class.getClassLoader(), new Class[] {Operate.class}, timingInvocationHandler)); // call method of proxy instance operate.operateMethod1(); System.out.println(); operate.operateMethod2(); System.out.println(); operate.operateMethod3(); } } 下面總結一下動態代理對象創建過程 // InvocationHandlerImpl 實現了 InvocationHandler 接口,並能實現方法調用從代理類到委托類的分派轉發 // 其內部通常包含指向委托類實例的引用,用於真正執行分派轉發過來的方法調用 InvocationHandler handler = new InvocationHandlerImpl(..); // 通過 Proxy 為包括 Interface 接口在內的一組接口動態創建代理類的類對象 Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); // 通過反射從生成的類對象獲得構造函數對象 Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); // 通過構造函數對象創建動態代理類實例 Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler }); 從上面可以看到,實際使用過程更加簡單,因為 Proxy 的靜態方法 newProxyInstance 已經為我們封裝了步驟 2 到步驟 4 的過程,所以簡化后的過程如下 // InvocationHandlerImpl 實現了 InvocationHandler 接口,並能實現方法調用從代理類到委托類的分派轉發 InvocationHandler handler = new InvocationHandlerImpl(..); // 通過 Proxy 直接創建動態代理類實例 Interface proxy = (Interface)Proxy.newProxyInstance( classLoader, new Class[] { Interface.class }, handler ); 參考文章: Java 動態代理機制分析 公共技術點之 Java 動態代理 代理模式和android插件化 Android設計模式源碼解析之Proxy模式