在之前的設計模式博文《設計模式_代理模式(Java)》中,介紹了代理模式。它是爲了提供額外的操作,而創建的用來替代實際對象的對象,原理和實現都較爲簡單,在這篇文章中我們主要是介紹Java中提供的動態代理。
動態代理比代理的思想更向前邁進一步,因爲它可以動態地創建代理,並動態地處理對所代理方法的調用。在動態代理上所做的所有調用都會被重定向到單一的調用處理器(InvocationHandler
實現)上。在Java中,動態代理是通過反射機制進行實現的。
下面我們來逐步分析一下Java動態代理的具體實現:
/**目標接口**/
interface Driver{
/**目標方法**/
public void run();
public void stop(String c);
}
/**目標對象**/
class RealDriver implements Driver{
public void run() {
System.out.println("car is running");
}
public void stop(String c) {
if(c.equals("girls")){
System.out.println("car is stopping");
}
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 動態代理處理器
* 在動態代理上所做的所有調用都會被重定向到該處理器
**/
public class DynamicProxyHandler implements InvocationHandler{
public Object target;
public DynamicProxyHandler(Object o){
this.target=o;
}
/**
* 執行目標對象的方法
* proxy: 代理對象被傳遞進來
* method: 被調用方法
* args: 方法參數
***/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//轉調之前處理
System.out.println("dididi~~~");
//轉調具體目標對象的方法
Object o=method.invoke(target, args);
//轉調之後處理
if(args!=null){
for(Object arg:args){
System.out.println(arg +" follow me, let's go!");
}
}
return o;
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**測試類**/
public class Test {
public static void main(String[] args) {
//目標對象實例化
Driver driver=new RealDriver();
//創建處理器對象
InvocationHandler invocationHandler=new DynamicProxyHandler(driver);
/**
* 獲取目標對象的代理對象
* !重點語句
* driver.getClass().getClassLoader() 獲取目標對象的類加載器
* driver.getClass().getInterfaces() 獲取目標對象的接口,或者是接口的列表,
* 但不可以是類和抽象類,原因是動態生成的代理對象已經繼承了Proxy類,無法繼承其他類或者抽象類(Java單繼承)
* invocationHandler 處理器對象
**/
Driver driverProxy=(Driver)Proxy.newProxyInstance(driver.getClass().getClassLoader(), driver.getClass().getInterfaces(), invocationHandler);
//調用代理對象方法
driverProxy.run();
driverProxy.stop("girls");
driverProxy.stop("ladys");
}
}
執行結果如下:
dididi~~~
car is running
dididi~~~
car is stopping
girls follow me, let's go!
dididi~~~
ladys follow me, let's go!
Spring的AOP實現其實也是通過這種方法進行的。
大家應該都注意到了再上述實現中的一些重點部分。一個是DynamicProxyHandler
類invoke()
方法中的Object o=method.invoke(target, args);
它將請求轉發給被代理的對象target
。另一個是main()
方法中的Driver driverProxy=(Driver)Proxy.newProxyInstance(driver.getClass().getClassLoader(), driver.getClass().getInterfaces(), invocationHandler);
具體參數的意義我們已經在代碼註釋中給出,我們重點分析Proxy.newProxyInstance()
中發生的事情,在Proxy.newProxyInstance()
中主要執行了以下三步:
//獲取代理對象引用
1. Class cl = getProxyClass(loader, interfaces);
//通過反射機制獲取動態代理類的構造函數,其參數類型是調用處理器接口類型
2. Constructor cons = cl.getConstructor(new Class[]{InvocationHandler.class});
//返回代理對象,h爲invocationHandler
3. return (Object) cons.newInstance(new Object[] { h });
生成的“driverProxy”繼承了Proxy類並實現了Driver目標接口,代理調用的方法實際調用處理器的invoke()方法,而invoke()方法利用反射調用的是被代理對象的的方法。
感覺比較神奇,是吧。但是Java中實現的動態代理仍存在問題,例如必須要求目標對象擁有其目標接口,否則無法實現代理,那麼很多場景下可能無法實現動態代理。cglib動態代理則解除了這種限制,並且有着較高的執行效率,我們在這裏就不對cglib動態代理進行介紹了,想了解的同學可以移步《Java動態代理機制詳解(JDK 和CGLIB,Javassist,ASM)》進行學習。
參考: