【Java中級篇】動態代理機制

要想搞明白動態代理之前,我們先來了解一下代理是什麼意思,先來談談設計模式中的代理模式。

什麼是代理模式(Proxy)

定義:給目標對象提供一個代理對象,並由代理對象控制對目標對象的引用。

在代理模式中,是需要代理對象和目標對象實現同一個接口(如果是不同的接口,那就是適配器模式了),看下面的UML圖

                                            

爲什麼要用代理

最最最主要的原因就是,在不改變目標對象方法的情況下對方法進行增強,比如,我們希望對方法的調用增加日誌記錄,或者對方法的調用進行攔截,等等...

舉一個例子

現有一個IPerson接口,只有一個方法say()

public interface IPerson {
    void say();
}

有一個Man類,實現了IPerson

public class Man implements IPerson{
    @Override
    public void say() {
        L.d("man say");
    }
}

現在需要在say方法被調用的時候,記錄方法被調用的時間,最直接的就是修改Man的say方法,但是這樣做的弊端就是如果有很多實現了IPerson接口的類,那就需要修改多處代碼,而且這樣的修改可能會導致其他的代碼出問題(可能並不是所有的say都需要記錄調用時間)。怎麼辦呢,這時候代理就要登場了!

靜態代理

public class ManProxy implements IPerson{

    private IPerson target;

    public IPerson getTarget() {
        return target;
    }

    public ManProxy setTarget(IPerson target) {
        this.target = target;
        return this;
    }

    @Override
    public void say() {
        if (target != null) {
            L.d("man say invoked at : " + System.currentTimeMillis());
            target.say();
        }
    }
}

這樣我們需要新建一個ManProxy類同樣實現IPerson接口,將要代理的對象傳遞進來,這樣就可以在不修改Man的say方法的情況下實現了我們的需求。這其實就是靜態代理。那你可能要問,既然有了靜態代理,爲什麼需要動態代理呢,因爲靜態代理有一個最大的缺陷:接口與代理類是1對1的,有多個接口需要代理,就需要新建多個代理類,繁瑣,類爆炸

動態代理

我們先嚐試用動態代理來解決上面的問題。先新建一個類實現InvocationHandler

public class NormalHandler implements InvocationHandler {

    private Object target;

    public NormalHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        L.d("man say invoked at : " + System.currentTimeMillis());
        method.invoke(target, args);
        return null;
    }
}

然後可以這樣使用

		NormalHandler normalHandler = new NormalHandler(new Man());
		IPerson iPerson = (IPerson) Proxy.newProxyInstance(IPerson.class.getClassLoader(),
		                new Class[] {IPerson.class}, normalHandler);
		iPerson.say();

可以看到NormalHandler中代理的對象是Object類型,所以它是被多個接口代理複用的,這樣就解決靜態代理類爆炸,維護困難的問題。

接着我們發現執行iPerson.say()時,會被攔截從而執行NormalHandler中的invoke方法。

總結

1、代理模式的概念

2、靜態代理和動態代理的區別

3、如何使用動態代理:

      3.1、創建被代理對象的接口IPerson 

      3.2、實現被代理的真實對象Man 

      3.3、創建調用處理器NormalHandler 

      3.4、生成代理對象

 

 

本文參考:https://blog.csdn.net/u011552404/article/details/79954199https://www.jianshu.com/p/6e962d1e7ddd

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