免费在线a视频-免费在线观看a视频-免费在线观看大片影视大全-免费在线观看的视频-色播丁香-色播基地

淺談Java動(dòng)態(tài)代理

:2019年05月09日 網(wǎng)絡(luò)
分享到:

代理模式相信了解設(shè)計(jì)模式的developer對(duì)代理(proxy pattern)模式都不陌生。代理模式的基本思想就是在調(diào)用者和被調(diào)用者之間加上一層“代理”,這層代理對(duì)于調(diào)用者而言是透明的,因?yàn)榇硗捅淮韺?duì)象...

代理模式

相信了解設(shè)計(jì)模式的developer對(duì)代理(proxy pattern)模式都不陌生。代理模式的基本思想就是在調(diào)用者和被調(diào)用者之間加上一層“代理”,這層代理對(duì)于調(diào)用者而言是透明的,因?yàn)榇硗捅淮韺?duì)象實(shí)現(xiàn)相同的借口。那么既然實(shí)現(xiàn)相同的接口,代理的意義又何在?因?yàn)槲覀兂3P枰谠镜慕涌谏戏庋b一些業(yè)務(wù)邏輯,比如日志、緩存、訪問控制等等,這些另外封裝的業(yè)務(wù)邏輯從設(shè)計(jì)的角度并不適宜直接封裝在原有的接口實(shí)現(xiàn)中,因?yàn)橹T如日志、緩存等并不屬于被代理對(duì)象的職責(zé);同時(shí),代理模式可以做到方便的修改和移除(設(shè)計(jì)模式的關(guān)鍵就是封裝變化)。這種模式在RMI和EJB中都得到了很好的體現(xiàn),包括spring的AOP中實(shí)現(xiàn)。傳統(tǒng)的代理模式需要在源代碼中添加一些附加的類,一般需要手工編寫或工具自動(dòng)生成。

動(dòng)態(tài)代理

java的動(dòng)態(tài)代理比代理的思想更進(jìn)了一步,因?yàn)樗梢詣?dòng)態(tài)的創(chuàng)建代理并動(dòng)態(tài)的處理對(duì)所代理方法的調(diào)用,在運(yùn)行時(shí)刻,可以動(dòng)態(tài)創(chuàng)建出一個(gè)實(shí)現(xiàn)了多個(gè)接口的代理類。每個(gè)代理類的對(duì)象都會(huì)關(guān)聯(lián)一個(gè)表示內(nèi)部處理邏輯的InvocationHandler 接 口的實(shí)現(xiàn)。當(dāng)使用者調(diào)用了代理對(duì)象所代理的接口中的方法的時(shí)候,這個(gè)調(diào)用的信息會(huì)被傳遞給InvocationHandler的invoke方法。在 invoke方法的參數(shù)中可以獲取到代理對(duì)象、方法對(duì)應(yīng)的Method對(duì)象和調(diào)用的實(shí)際參數(shù)。invoke方法的返回值被返回給使用者。這種做法實(shí)際上相 當(dāng)于對(duì)方法調(diào)用進(jìn)行了攔截。下面以一個(gè)簡(jiǎn)單的示例來說明java動(dòng)態(tài)代理: 

接口定義:

interface DoSomething {

    void doSomething();

    void doSomethingElse(String arg);

}

實(shí)現(xiàn)接口的類,也即被代理的類:

class RealObject implements DoSomething {

    @Override

    public void doSomething() {

        System.out.println("realObject doSomething");

    }

    @Override

    public void doSomethingElse(String arg) {

        System.out.println("realObject doSomethingElse " + arg);

    }

}

動(dòng)態(tài)代理的處理類,需要實(shí)現(xiàn)InvocationHandler接口:

class DynamicProxyHander implements InvocationHandler {

    // 被代理類,將其作為實(shí)例變量在構(gòu)造函數(shù)中傳入

    private Object proxied;

    public DynamicProxyHander(Object proxied) {

        this.proxied = proxied;

    }

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("***** proxy: " + proxy.getClass().getSimpleName() + "method :" + method + "args: " + args);

        if (null != args) {

            for (Object arg : args) {

                System.out.println(" " + arg);

            }

        }

        return method.invoke(proxied, args);

    }

}

調(diào)用RealObject和調(diào)用動(dòng)態(tài)代理生成對(duì)象:

public class DynamicProxyDemo{

    public static void consume(DoSomething doSomething){

        doSomething.doSomething();

        doSomething.doSomethingElse("bonbo");

    }

    public static void main(String[] args) {

        RealObject real = new RealObject();

        consume(real);

        DoSomething proxy = (DoSomething)Proxy.newProxyInstance(DoSomething.class.getClassLoader(),

            new Class[]{DoSomething.class}, new DynamicProxyHander(real));

        consume(proxy);

    }

}

通過調(diào)用Proxy.newProxyInstance可以創(chuàng)建動(dòng)態(tài)代理,這個(gè)方法需要一個(gè)類加載器,一個(gè)希望該代理實(shí)現(xiàn)的接口列表,以及InvocationHandler的一個(gè)實(shí)現(xiàn)。動(dòng)態(tài)代理可以將所有的調(diào)用重定向到調(diào)用處理器,因此通常會(huì)向調(diào)用處理器的構(gòu)造器傳遞一個(gè)實(shí)際對(duì)象的引用,從而使動(dòng)態(tài)代理處理中介任務(wù)時(shí),可以將請(qǐng)求轉(zhuǎn)發(fā)。

動(dòng)態(tài)代理與字節(jié)碼生成技術(shù)

上面說的是動(dòng)態(tài)代理的基本用法,相信許多java開發(fā)者都使用過動(dòng)態(tài)代理,即使沒有直接 使用過java.lang.reflect.Proxy或?qū)崿F(xiàn)過InvocationHandler接口,也應(yīng)該使用過spring做過Bean的管理。如果使用過Spring,那大多數(shù)情況下都會(huì)用過動(dòng)態(tài)代理,因?yàn)槿绻鸼ean是面向接口編程,那么在spring內(nèi)部都是用動(dòng)態(tài)代理對(duì)bean進(jìn)行增強(qiáng)的。動(dòng)態(tài)代理中所謂的動(dòng)態(tài),是針對(duì)代碼實(shí)際編寫了代理的“靜態(tài)”而言的,動(dòng)態(tài)代理的優(yōu)勢(shì)不在于減少了那一點(diǎn)的編碼量,而是實(shí)現(xiàn)了在原始類和接口未知的時(shí)候,就確定代理的代理行為,當(dāng)代理類和原始類脫離直接聯(lián)系后,就可以和靈活的重用到不同的應(yīng)用場(chǎng)景中。 

在上述的代碼里,唯一的黑匣子就是Proxy.newProxyInstance方法,除此之外并無任何特別之處。這個(gè)方法返回了一個(gè)實(shí)現(xiàn)了DoSomething的接口。跟蹤這個(gè)方法的源碼:

public static Object newProxyInstance(ClassLoader loader,

                                          Class<?>[] interfaces,

                                          InvocationHandler h)

        throws IllegalArgumentException

    {

        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();

        final SecurityManager sm = System.getSecurityManager();

        if (sm != null) {

            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);

        }

        /*

         * Look up or generate the designated proxy class.

         */

        Class<?> cl = getProxyClass0(loader, intfs);

        /*

         * Invoke its constructor with the designated invocation handler.

         */

        try {

            if (sm != null) {

                checkNewProxyPermission(Reflection.getCallerClass(), cl);

            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);

            final InvocationHandler ih = h;

            if (!Modifier.isPublic(cl.getModifiers())) {

                AccessController.doPrivileged(new PrivilegedAction<Void>() {

                    public Void run() {

                        cons.setAccessible(true);

                        return null;

                    }

                });

            }

            return cons.newInstance(new Object[]{h});

        } catch (IllegalAccessException|InstantiationException e) {

            throw new InternalError(e.toString(), e);

        } catch (InvocationTargetException e) {

            Throwable t = e.getCause();

            if (t instanceof RuntimeException) {

                throw (RuntimeException) t;

            } else {

                throw new InternalError(t.toString(), t);

            }

        } catch (NoSuchMethodException e) {

            throw new InternalError(e.toString(), e);

        }

    }

我們可以看到程序進(jìn)行了驗(yàn)證、優(yōu)化、緩存、同步、生成字節(jié)碼、顯式類加載等操作,最后調(diào)用了sun.misc.ProxyGenerator.generateProxyClass方法來完成生成字節(jié)碼的動(dòng)作(上述源代碼只貼出了主方法,詳細(xì)步驟有興趣的讀者可以參閱java.lang.reflect.Proxy源代碼)。這個(gè)方法可以在運(yùn)行時(shí)產(chǎn)生一個(gè)描述代理類的字節(jié)碼byte[]數(shù)組。大致的生成過程其實(shí)就是根據(jù).class文件的格式規(guī)范去拼裝字節(jié)碼,但在實(shí)際開發(fā)中,直接生成字節(jié)碼的例子極為少見,如果有大量操作字節(jié)碼的需求,還是使用封裝好的字節(jié)碼類庫比較合適。(關(guān)于字節(jié)碼格式以及類加載過程,讀者可以自行查閱資料學(xué)習(xí))

動(dòng)態(tài)代理的運(yùn)用

動(dòng)態(tài)代理由于本身靈活的特性,在Java技術(shù)棧中得到了非常多的運(yùn)用。比如為java開發(fā)者所熟悉的spring框架,其AOP本質(zhì)上也是動(dòng)態(tài)代理。包括hadoop RPC在內(nèi)的許多RPC框架也大量運(yùn)用了動(dòng)態(tài)代理,在日后的學(xué)習(xí)和實(shí)踐中,會(huì)多多關(guān)注所運(yùn)用的工具和框架的實(shí)現(xiàn)機(jī)制,若有所感悟和收獲,會(huì)記錄一下以供總結(jié)和分享。

[我要糾錯(cuò)]
[編輯:宋聰喬 &發(fā)表于江蘇]
關(guān)鍵詞: 代理 模式 相信 了解 設(shè)計(jì)模式

來源:本文內(nèi)容搜集或轉(zhuǎn)自各大網(wǎng)絡(luò)平臺(tái),并已注明來源、出處,如果轉(zhuǎn)載侵犯您的版權(quán)或非授權(quán)發(fā)布,請(qǐng)聯(lián)系小編,我們會(huì)及時(shí)審核處理。
聲明:江蘇教育黃頁對(duì)文中觀點(diǎn)保持中立,對(duì)所包含內(nèi)容的準(zhǔn)確性、可靠性或者完整性不提供任何明示或暗示的保證,不對(duì)文章觀點(diǎn)負(fù)責(zé),僅作分享之用,文章版權(quán)及插圖屬于原作者。

點(diǎn)個(gè)贊
0
踩一腳
0

您在閱讀:淺談Java動(dòng)態(tài)代理

Copyright©2013-2025 ?JSedu114 All Rights Reserved. 江蘇教育信息綜合發(fā)布查詢平臺(tái)保留所有權(quán)利

蘇公網(wǎng)安備32010402000125 蘇ICP備14051488號(hào)-3技術(shù)支持:南京博盛藍(lán)睿網(wǎng)絡(luò)科技有限公司

南京思必達(dá)教育科技有限公司版權(quán)所有   百度統(tǒng)計(jì)

主站蜘蛛池模板: 阿v天堂2021在线观看 | 欧美大黄视频 | 国产亚洲精品观看91在线 | 久久狠狠色噜噜狠狠狠狠97 | 亚洲欧美综合在线观看 | 在线观看亚洲天堂 | 欧美成人综合 | 日韩欧美不卡一区二区三区 | 一区二区视频在线观看免费的 | 一级做a爱过程免费视频韩国 | 精品国产免费一区二区 | 曰鲁夜鲁鲁狠狠综合 | 亚洲欧美日本在线观看 | 在线观看亚洲欧美 | 国外成人免费高清激情视频 | 秋霞国产在线 | 亚洲国产成人九九综合 | 中文字幕一区二区三区 精品 | 日韩精品成人a在线观看 | 手机在线观看毛片 | 97人洗澡人人澡人人爽人人 | 日韩国产成人 | 欧美在线一级精品 | 国产二区在线播放 | 日韩欧美一区黑人vs日本人 | 日韩欧美视频在线播放 | 天天干天天色天天射 | 成人无遮挡免费网站视频在线观看 | 动漫精品一级毛片动漫 | 综合网激情五月 | 99视频在线观看免费视频 | 日韩精品1区 | 一男四女乱肉荒岛小说 | 一区二区三区视频在线观看 | 色婷婷激情五月综合 | 成人精品一区二区不卡视频 | 诱人的护士5中文字幕 | 欧美激情在线观看一区二区三区 | 亚州国产| 天天摸日日 | 午夜影院色 |
最熱文章
最新文章
  • 阿里云上云鉅惠,云產(chǎn)品享最低成本,有需要聯(lián)系,
  • 卡爾蔡司鏡片優(yōu)惠店,鏡片價(jià)格低
  • 蘋果原裝手機(jī)殼