動(dòng)態(tài)代理是代理模式的補(bǔ)充,傳統(tǒng)的代理模式要求我們?yōu)榇眍悇?chuàng)建class文件(.java文件編譯后的字節(jié)流),相對(duì)麻煩,動(dòng)態(tài)代理可以省去這個(gè)步驟,在運(yùn)行時(shí)生成和class文件等價(jià)的字節(jié)流,然后加載到JVM中。本文參考了http://www.lxweimin.com/p/6f6bb2f0ece9# ,在他之上增加了類圖和自己的理解。
老規(guī)矩,向上一張類圖。
類圖
實(shí)例
public class Main {
public static void main(String args[]) {
Subject realSubject = new RealSubject(); //創(chuàng)建委托對(duì)象
ProxyHandler proxyHandler = new ProxyHandler(realSubject); //創(chuàng)建InvocationHandler對(duì)象
Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader()
, realSubject.getClass().getInterfaces()
, proxyHandler); //生成代理對(duì)象
proxy.request(); //使用代理對(duì)象
}
}
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就是生成的代理對(duì)象
throws Throwable {
System.out.println("====before===="); //定義預(yù)處理的工作,當(dāng)然你也可以根據(jù) method的不同進(jìn)行不同的預(yù)處理工作
Object result = method.invoke(subject, args);
System.out.println("====after====");
return result;
}
}
------------------------------輸出---------------------------------------
====before====
real request
====after====
結(jié)合類圖,我們首先創(chuàng)建一個(gè)RealSubject對(duì)象,一個(gè)ProxyHandler對(duì)象,這個(gè)對(duì)象的類繼承自InvocationHandler,invoke(Object proxy, Method method, Object[] args)
第一個(gè)參數(shù)proxy就是由反射創(chuàng)建的代理對(duì)象,第二參數(shù)表明代理對(duì)象調(diào)用的方法,第三個(gè)參數(shù)表示調(diào)用的參數(shù),在這個(gè)方法里我們調(diào)用了realSubject的對(duì)應(yīng)的方法,在之前和之后我們都可以做相應(yīng)的操作,這正是代理的含義。那個(gè)這個(gè)invoke(Object proxy, Method method, Object[] args)
是什么時(shí)候調(diào)用的?答案是proxy.request();
這個(gè)方法是自動(dòng)生成的,內(nèi)部實(shí)現(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對(duì)象
return (Integer)h.invoke(this, method, new Object[]{new Integer(i)}); //調(diào)用了invoke方法
}
}
這個(gè)方法將代理對(duì)象作為參數(shù)傳遞給InvocationHandler.invoke方法。所以調(diào)用鏈如下:proxy.request()--->InvocationHandler.invoke()。再結(jié)合類圖就不難理解。