動(dòng)態(tài)代理使用不在累述。InvocationHandler.invoke的第一個(gè)參數(shù)proxy值是newProxyInstance返回的動(dòng)態(tài)代理類的實(shí)例鸳谜,不是被代理的實(shí)例。
動(dòng)態(tài)代理類Proxy是結(jié)合java底層實(shí)現(xiàn)的,通過純粹的java代碼實(shí)現(xiàn)比較困難朝巫。
需要java動(dòng)態(tài)生成類的支持。
要?jiǎng)?chuàng)建一個(gè)可以代理任何接口的類:
1.必須要知道要被代理的接口列表滥酥;
2.要有一個(gè)可以加載這個(gè)代理類的ClassLoader更舞;
3.為了能夠在調(diào)用被代理實(shí)例接口時(shí)能夠動(dòng)態(tài)的添加需要的處理,需要一個(gè)接口回調(diào)坎吻,并在回調(diào)中采用反射的形式調(diào)用實(shí)際的實(shí)例方法缆蝉。
實(shí)現(xiàn)過程:以下Proxy是實(shí)現(xiàn)動(dòng)態(tài)代理的過程
public interface Subject{
public void rent();
public void hello(String str);
}
public class RealSubject implements Subject{
@Override
public void rent() {
System.out.println("I want to rent my house");
}
@Override
public void hello(String str) {
System.out.println("hello: " + str);
}
}
public class DynamicProxyHandler implements InvocationHandler {
// 被代理對象
private Object subject;
public DynamicProxy(Object subject) {
this.subject = subject;
}
@Override
public Object invoke(Object object, Method method, Object[] args) throws Throwable {
// 在代理真實(shí)對象前我們可以添加一些自己的操作
System.out.println("Method:" + method);
// 當(dāng)代理對象調(diào)用真實(shí)對象的方法時(shí),其會自動(dòng)的跳轉(zhuǎn)到代理對象關(guān)聯(lián)的handler對象的invoke方法來進(jìn)行調(diào)用
method.invoke(subject, args);
// 在代理真實(shí)對象后我們也可以添加一些自己的操作
System.out.println("after rent house");
return null;
}
}
public static void main(String[] args) {
Subject realSubject = new RealSubject();
InvocationHandler handler = new DynamicProxyHandler(realSubject);
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
.getClass().getInterfaces(), handler);
System.out.println(subject.getClass().getName());
subject.rent();
subject.hello("world");
}
subject.getClass().getName()打印的值是:$Proxy0
猜測大概的$Proxy0類如下(可以通過反射查看其中的一部分實(shí)際內(nèi)容):
// 類的包名應(yīng)該是和Proxy在同一個(gè)包下
public class Proxy0 implements Subject {
private InvocationHandler handler;
public Proxy0(InvocationHandler handler) {
this.handler = handler;
}
public void rent() {
Thread.currentThread().getStackTrace()[2].getMethodName();
// 通過反射獲取當(dāng)前函數(shù)名稱和參數(shù)列表瘦真,傳給invoke
Proxy.invoke(this, method, args);
}
public void hello(String str) {
Proxy.invoke(this, method, args);
}
}
InvocationHandler的實(shí)現(xiàn)可以多種多樣刊头,根據(jù)不同需求進(jìn)行不同實(shí)現(xiàn)。