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

抽象對象角色:就是代理類和委托類共同的接口,聲明了目標對象和代理對象的共同接口,這樣一來在任何可以使用目標對象的地方都可以使用代理對象。
目標對象角色:就是委托類,定義了代理對象所代表的目標對象。
代理對象角色:就是代理類,代理對象內部含有目標對象的引用,從而可以在任何時候操作目標對象;代理對象提供一個與目標對象相同的接口,以便可以在任何時候替代目標對象。代理對象通常在客戶端調用傳遞給目標對象之前或之后,執行某個操作,而不是單純地將調用傳遞給目標對象。
靜態代理
代理類在程序運行前已經存在的代理方式稱為靜態代理。
/**
* 定義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模式