代理設計在Java開發中使用較多的一種設計模式,所謂的代理設計就是指由一個代理主題來操作真實主題,真實主題執行具體的業務操作,而代理主題負責其他相關業務的處理。
先來看看靜態代理
1 package com.proxy.inter; 2 3 /** 4 * 定義Demo接口 5 */ 6 public interface Demo { 7 public void save(); 8 }
1 package com.proxy.impl; 2 3 import com.proxy.inter.Demo; 4 5 /** 6 * DemoImpl實現Demo接口並覆寫save()方法 7 * 真實主題,執行具體業務 8 */ 9 public class DemoImpl implements Demo { 10 public void save() { 11 System.out.println("調用save()方法"); 12 } 13 }
1 package com.proxy.impl; 2 3 import com.proxy.inter.Demo; 4 /** 5 * DemoImplProxy 也實現了Demo接口,並覆寫了save()方法,增加了自己的業務 6 * 代理主題,負責其他業務的處理 7 */ 8 public class DemoImplProxy implements Demo { 9 Demo demoImpl = new DemoImpl(); 10 11 public void save() { 12 System.out.println("開始記錄日志"); 13 demoImpl.save(); 14 System.out.println("開始結束日志"); 15 } 16 }
1 package com.proxy.impl; 2 3 import com.proxy.inter.Demo; 4 5 /** 6 * 開始記錄日志 7 * 調用save()方法 8 * 開始結束日志 9 */ 10 public class Test { 11 public static void main(String[] args) { 12 Demo demoImplProxy = new DemoImplProxy(); 13 14 demoImplProxy.save(); 15 } 16 }
你會發現每個代理類只能為一個接口服務,這樣程序開發中必然會產生許多的代理類
所以我們就會想辦法可以通過一個代理類完成全部的代理功能,那么我們就需要用動態代理
在Java中要想實現動態代理機制,需要java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 類的支持
java.lang.reflect.InvocationHandler接口的定義如下:
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
Object proxy:被代理的對象
Method method:要調用的方法
Object[] args:方法調用時所需要參數
java.lang.reflect.Proxy類的定義如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
CLassLoader loader:類的加載器
Class<?> interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子類的實例
下面來看看動態代理的具體實現
1 package com.proxy.inter; 2 3 /** 4 * 定義DemoFirst接口 5 */ 6 public interface DemoFirst { 7 public void saveFirst(); 8 }
1 package com.proxy.impl; 2 3 import com.proxy.inter.DemoFirst; 4 5 /** 6 * DemoFirstImpl實現DemoFirst接口,覆寫saveFirst()方法 7 * 真實主題,負責執行具體業務 8 */ 9 public class DemoFirstImpl implements DemoFirst { 10 11 @Override 12 public void saveFirst() { 13 System.out.println("調用saveFirst()方法"); 14 } 15 16 }
1 package com.proxy.impl; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 /** 7 * InvocationHandlerImple實現InvocationHandler接口,覆寫invoke()方法 8 * 代理主題的業務寫在invoke()方法中 9 */ 10 public class InvocationHandlerImpl implements InvocationHandler { 11 12 private Object target; 13 14 public InvocationHandlerImpl(Object target) { 15 this.target = target; 16 } 17 18 @Override 19 public Object invoke(Object proxy, Method method, Object[] args) 20 throws Throwable { 21 System.out.println("target : " + target.getClass().getName()); 22 System.out.println("proxy : " + proxy.getClass().getName()); 23 System.out.println("method : " + method.getName()); 24 System.out.println("args : " + args); 25 System.out.println("開始記錄日志"); 26 Object obj = method.invoke(target, args); 27 System.out.println("結束記錄日志"); 28 /* 29 * System.out.println("obj : " + obj.getClass().getName()); 30 * 本例中saveXXX方法沒有返回值所以obj會報空指針異常 31 */ 32 return obj; 33 } 34 }
1 package com.proxy.impl; 2 3 import java.lang.reflect.Proxy; 4 5 import com.proxy.inter.DemoFirst; 6 /*import com.proxy.inter.DemoSecond;*/ 7 8 public class Test { 9 public static void main(String[] args) { 10 DemoFirst first = new DemoFirstImpl(); 11 /*DemoSecond second = new DemoSecondImpl();*/ 12 13 //取得代理對象 14 DemoFirst firstProxy = (DemoFirst) Proxy.newProxyInstance(first 15 .getClass().getClassLoader(), first.getClass().getInterfaces(), 16 new InvocationHandlerImpl(first)); 17 //通過動態代理調用方法 18 firstProxy.saveFirst(); 19 20 /*DemoSecond secondProxy = (DemoSecond) Proxy.newProxyInstance(second 21 .getClass().getClassLoader(), second.getClass().getInterfaces(), 22 new InvocationHandlerImpl(second)); 23 secondProxy.saveSecond();*/ 24 } 25 }
執行結果如圖:

如果我們需要動態代理demoSecond對象,只需要像上面注釋部分那樣即可
執行結果如圖:

我們會發現代理類Proxy會動態分配proxy對象,如圖$Proxy0,$Proxy1...
動態代理的應用在很多地方都由體現,比如在開源框架Spring中的AOP(面向切面編程)...
