動(dòng)態(tài)代理是什么
在Java API手冊(cè)中原話是這樣介紹動(dòng)態(tài)代理的:
Using Java Reflection to create dynamic implementations of interfaces at runtime.
按我的理解,動(dòng)態(tài)代理就是利用Java的反射機(jī)制,在運(yùn)行時(shí)創(chuàng)建一個(gè)實(shí)現(xiàn)某些給定接口的新類(也稱“動(dòng)態(tài)代理類”)及其實(shí)例(對(duì)象)。
換句話說,代理的是接口(Interfaces),不是類(Class),更不是抽象類。
這正是面向接口編程的關(guān)鍵所在。
動(dòng)態(tài)代理應(yīng)用
- AOP中的面向切面編程
- 適配器(Adapter)或修飾器(Decorator)設(shè)計(jì)模式
動(dòng)態(tài)代理的創(chuàng)建
在Java API手冊(cè)Proxy類告訴我們,創(chuàng)建動(dòng)態(tài)代理有兩種方式
InvocationHandler handler = new MyInvocationHandler(...);
//方式一
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(),Foo.class);
Foo f =(Foo)proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
//方式二 本文探究的方式
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
Proxy.newProxyInstance()方法有三個(gè)參數(shù):
類加載器
需要實(shí)現(xiàn)的接口數(shù)組
InvocationHandler接口實(shí)現(xiàn)類。
代理生成時(shí),會(huì)通過類加載器(Class Loader)獲取被代理接口的相關(guān)資源,定義了由哪個(gè)ClassLoader對(duì)象來對(duì)生成的代理對(duì)象。代理會(huì)實(shí)現(xiàn)接口數(shù)組(interfaces)里的所有接口,這樣我們就可以調(diào)用這組接口中的方法,或者將代理轉(zhuǎn)換成其中一個(gè)接口。最后,進(jìn)行加載所有動(dòng)態(tài)代理類的方法調(diào)用,都會(huì)交由InvocationHandler接口實(shí)現(xiàn)類里的重寫(override)后的invoke()方法去處理。這是動(dòng)態(tài)代理的關(guān)鍵所在。
接下來我們來探究,實(shí)現(xiàn)動(dòng)態(tài)代理時(shí)究竟代理了什么。
事前準(zhǔn)備
車輛接口:
public interface IVehicle {
void run(String s);
}
單車類:
public class Bicycle implements IVehicle {
@Override
public void run(String s) {
System.out.println( s + "Bicycle is running");
}
}
代理類:
public class VehicleProxy {
private IVehicle vehicle; //被代理接口
public VehicleProxy(IVehicle vehicle) {
this.vehicle = vehicle;
}
public IVehicle create(){ //創(chuàng)建代理方法
final Class<?>[] interfaces = new Class[]{IVehicle.class};
final VehicleInvocationHandler handler = new VehicleInvocationHandler(vehicle);
return (IVehicle) Proxy.newProxyInstance(IVehicle.class.getClassLoader(), interfaces, handler);
}
}
InvocationHandler實(shí)現(xiàn)類:
public class VehicleInvocationHandler implements InvocationHandler {
private final IVehicle vehicle;
public VehicleInvocationHandler(IVehicle vehicle) {
this.vehicle = vehicle;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("--before running...");
Object ret = method.invoke(vehicle, args);
System.out.println("--after running...");
return ret;
}
}
測(cè)試方法
public class ProxyTest {
public static void main(String[] args){
IVehicle bicycle = new Bicycle();
VehicleProxy proxy = new VehicleProxy(bicycle);
IVehicle proxyObj = proxy.create();
proxyObj.run("BMW"); //寶馬確實(shí)生成過單車
}
}
結(jié)果:
--before running...
BMW Bicycle is running
--after running...
可以看到,對(duì)IVehical接口的調(diào)用,會(huì)交由Proxy的invoke方法處理,并在不改變r(jià)un()的源代碼下,新增了動(dòng)態(tài)的邏輯(before running/after running)。AOP正是利用這個(gè)原理做的。
我們?cè)偻ㄟ^debug看看代理調(diào)用方法過程中,代理對(duì)象是如何生成的,數(shù)據(jù)是如何傳遞的。
可以看出,通過create方法中調(diào)用Proxy.newProxyInstance,proxyObj接口獲得了一個(gè)代理類。觀察圖2的proxy值我們發(fā)現(xiàn),這代理類的名字有點(diǎn)特別,是以$開頭的。這是動(dòng)態(tài)代理的命名體現(xiàn),證明這個(gè)類是繼承Proxy類的代理類,而它現(xiàn)在充當(dāng)著IVehicle的角色。
調(diào)用再進(jìn)入到proxyObj.run("BMW");方法時(shí),會(huì)觸發(fā)InvocationHandler實(shí)現(xiàn)類中的invoke方法。從debug逐個(gè)分析invoke方法獲得的三個(gè)參數(shù):
- proxy:與proxyObj名字相同,即代理類的實(shí)例引用,它里面存放著被代理對(duì)象vehicle
- method: 實(shí)際被代理類的方法,在例子里是run()方法
- args: 實(shí)際是代理proxyObj.run("BMW");的參數(shù),可以用于傳給被代理方法調(diào)用