1. 程式人生 > 實用技巧 >Java反射02——動態代理

Java反射02——動態代理

本文不涉及靜態代理,只涉及動態代理,本人見過將動態代理講的比較好的文章在底部,有興趣的讀者可以移步。
老步驟:

1.什麼是動態代理?

通俗的講,動態代理就是建立一個類的代理物件,當需要訪問這個類的某些方法時,可以通過呼叫代理物件的同名方法,而真正實現的確實這個類的方法。

2.為什麼需要動態代理?

a.設計模式中有一個設計原則是開閉原則,是說對修改關閉對擴充套件開放,我們在工作中有時會接手很多前人的程式碼,裡面程式碼邏輯讓人摸不著頭腦(sometimes the code is really like shit),這時就很難去下手修改程式碼,那麼這時我們就可以通過代理對類進行增強。

b.我們在使用RPC框架的時候,框架本身並不能提前知道各個業務方要呼叫哪些介面的哪些方法 。那麼這個時候,就可用通過動態代理的方式來建立一箇中間人給客戶端使用,也方便框架進行搭建邏輯,某種程度上也是客戶端程式碼和框架鬆耦合的一種表現。

c.Spring的AOP機制就是採用動態代理的機制來實現切面程式設計。[1]

3.怎麼實現動態代理?

想要實現動態代理,需要解決兩個問題
(1)如何根據被載入到記憶體中的被代理類,動態地建立代理類及其物件;
(2)當通過代理類的物件呼叫方法時,如何動態的呼叫被代理類中的同名方法;
其實直接以例項來說明是最好的,下面以人和超人為例來講解:
(1)先建立一個介面,裡面有兩個抽象方法

interface Human {
    String eat(String food);
    String word();
}

(2)某個類實現這個介面

class SuperMan implements Human{
    @Override
    public String eat(String food) {
        return "超人最愛吃:" + food;
    }

    @Override
    public String word() {
        return "超人專門打怪獸";
    }
}

(3)建立一個專門生成代理類工廠
PS:學習動態代理之前一定要理解Java反射機制,不然很多地方沒法弄懂

class HumanProxyFactory {
    /**
     * 傳入被代理類,返回一個代理類物件
     * @param obj
     * @return
     */
    public static Object createProxy(Object obj) {
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        myInvocationHandler.bind(obj);
        Object proxyInstance = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), myInvocationHandler);
        return proxyInstance;
    }
}

上面最關鍵的行在於createProxy方法的第四行,也就是如何生成一個代理類的物件(ProxyInstance),這裡使用了Java API自帶的一個類java.lang.reflect.Proxy,有興趣的同學的可以直接看JDK的原始碼,本人也沒看過。Proxy類中存在一個專門建立代理類的函式newProxyInstance,這裡面有三個引數,分別是被代理類的類載入器,被代理類實現的介面,以及一個實現了InvocationHandler介面的物件,前兩個引數只要掌握了反射就能理解,重點在於第三個引數,所以下面需要自己寫一個類來實現InvocationHandler介面。
(4)實現InvocationHandler介面

/**
 * 自己實現一個InvocationHandler介面,當代理類呼叫自己的方法時,實現的卻是被代理類的方法
 */
class MyInvocationHandler implements InvocationHandler {
    Object obj;
    public void bind(Object obj) {
        this.obj = obj;
    }
    /**
     * 傳入的是代理類物件,代理類物件的方法,以及該方法中的引數陣列
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        /* 這裡的返回值,實際上是被代理類呼叫此方法的返回值,可以為null */
        Object o = method.invoke(obj, args);
        return o;
    }
}

(5)在測試類中檢驗結果

public class ProxyTest {
    public static void main(String[] args) {
        Human proxy = (Human) HumanProxyFactory.createProxy(new SuperMan());
        String s = proxy.eat("牛排");
        System.out.println(s);
    }
}

結果如下:

以上就是動態代理的基本原理

參考文章

[1]java動態代理實現與原理詳細分析