從代理模式到Java動態代理

在之前的設計模式博文《設計模式_代理模式(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實現其實也是通過這種方法進行的。

大家應該都注意到了再上述實現中的一些重點部分。一個是DynamicProxyHandlerinvoke()方法中的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)》進行學習。

參考:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章