初探j(luò)ava動(dòng)態(tài)代理

動(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ù):

  1. 類加載器

  2. 需要實(shí)現(xiàn)的接口數(shù)組

  3. 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ù)是如何傳遞的。


image.png

image.png

可以看出,通過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的角色。

image.png

image.png

調(diào)用再進(jìn)入到proxyObj.run("BMW");方法時(shí),會(huì)觸發(fā)InvocationHandler實(shí)現(xiàn)類中的invoke方法。從debug逐個(gè)分析invoke方法獲得的三個(gè)參數(shù):

  1. proxy:與proxyObj名字相同,即代理類的實(shí)例引用,它里面存放著被代理對(duì)象vehicle
  2. method: 實(shí)際被代理類的方法,在例子里是run()方法
  3. args: 實(shí)際是代理proxyObj.run("BMW");的參數(shù),可以用于傳給被代理方法調(diào)用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 原文: Dyanmic Proxy Classes 介紹 一個(gè)動(dòng)態(tài)代理類是實(shí)現(xiàn)了多個(gè)接口存在于運(yùn)行時(shí)的類,這樣,一...
    半黑月缺閱讀 959評(píng)論 0 0
  • title: Jdk動(dòng)態(tài)代理原理解析 tags:代理 categories:筆記 date: 2017-06-14...
    行徑行閱讀 19,322評(píng)論 3 36
  • Java代理和動(dòng)態(tài)代理機(jī)制分析和應(yīng)用 概述 代理是一種常用的設(shè)計(jì)模式,其目的就是為其他對(duì)象提供一個(gè)代理以控制對(duì)某個(gè)...
    丸_子閱讀 3,050評(píng)論 6 57
  • 總喜歡一個(gè)人漫步在雨中,抬起頭想來雙臂迎接著雨水的猛烈襲擊,順著臉的輪廓,劃過嘴角滴落下來,感覺一切都釋然了。 ...
    晴妁閱讀 1,202評(píng)論 2 8
  • 無論社會(huì)的文明程度發(fā)展到什么時(shí)候,人類的自私本性都不會(huì)完全消除,只是更加學(xué)會(huì)掩飾自己的行為,更加虛偽以各種理...
    痖鏞閱讀 135評(píng)論 0 1