動態(tài)代理是代理模式的補充,傳統(tǒng)的代理模式要求我們?yōu)榇眍悇?chuàng)建class文件(.java文件編譯后的字節(jié)流),相對麻煩,動態(tài)代理可以省去這個步驟,在運行時生成和class文件等價的字節(jié)流,然后加載到JVM中。本文參考了http://www.itdecent.cn/p/6f6bb2f0ece9# ,在他之上增加了類圖和自己的理解。
老規(guī)矩,向上一張類圖。
類圖

DynamicProxy.png
實例
public class Main {
public static void main(String args[]) {
Subject realSubject = new RealSubject(); //創(chuàng)建委托對象
ProxyHandler proxyHandler = new ProxyHandler(realSubject); //創(chuàng)建InvocationHandler對象
Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader()
, realSubject.getClass().getInterfaces()
, proxyHandler); //生成代理對象
proxy.request(); //使用代理對象
}
}
interface Subject {
public void request();
}
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("real request");
}
}
class ProxyHandler implements InvocationHandler{
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) //proxy就是生成的代理對象
throws Throwable {
System.out.println("====before===="); //定義預處理的工作,當然你也可以根據(jù) method的不同進行不同的預處理工作
Object result = method.invoke(subject, args);
System.out.println("====after====");
return result;
}
}
------------------------------輸出---------------------------------------
====before====
real request
====after====
結(jié)合類圖,我們首先創(chuàng)建一個RealSubject對象,一個ProxyHandler對象,這個對象的類繼承自InvocationHandler,invoke(Object proxy, Method method, Object[] args)第一個參數(shù)proxy就是由反射創(chuàng)建的代理對象,第二參數(shù)表明代理對象調(diào)用的方法,第三個參數(shù)表示調(diào)用的參數(shù),在這個方法里我們調(diào)用了realSubject的對應的方法,在之前和之后我們都可以做相應的操作,這正是代理的含義。那個這個invoke(Object proxy, Method method, Object[] args)是什么時候調(diào)用的?答案是proxy.request();這個方法是自動生成的,內(nèi)部實現(xiàn)類似
public final class $Proxy1 extends Proxy implements Subject{
private InvocationHandler h;
private $Proxy1(){}
public $Proxy1(InvocationHandler h){
this.h = h;
}
public int request(int i){
Method method = Subject.class.getMethod("request", new Class[]{int.class}); //創(chuàng)建method對象
return (Integer)h.invoke(this, method, new Object[]{new Integer(i)}); //調(diào)用了invoke方法
}
}
這個方法將代理對象作為參數(shù)傳遞給InvocationHandler.invoke方法。所以調(diào)用鏈如下:proxy.request()--->InvocationHandler.invoke()。再結(jié)合類圖就不難理解。