深入剖析java代理模式

      網(wǎng)友投稿 661 2022-05-29

      Java中代理模式有著廣泛的應(yīng)用,AOP就是最典型的應(yīng)用。

      Java中代理模式一般涉及到的角色有

      1、抽象角色:一般是個接口,Java原生的代理模式也只支持接口代理

      2、真實角色:實現(xiàn)抽象接口的真實類,又叫委托類。

      3、代理角色:代理角色內(nèi)部包含了真實角色的引用,且實現(xiàn)了與真實角色相同的接口,相當(dāng)于對真實角色進(jìn)行了封裝。這樣,代理角色可以執(zhí)行真實角色的操作,還能額外附加自己的操作。

      靜態(tài)代理

      我們通過代碼,實現(xiàn)一個簡單的靜態(tài)代理。模擬一個場景,網(wǎng)易為暴雪代理魔獸世界。

      抽象接口:魔獸世界——Wow

      -

      Java 代碼

      -

      查看代碼打印?

      接口中一個待實現(xiàn)的方法:TBC(燃燒的遠(yuǎn)征)

      實現(xiàn)類:暴雪——Blizzard

      Java 代碼

      查看代碼打印?

      實現(xiàn)類很簡單,暴雪自己實現(xiàn)了tbc這個接口,開始燃燒的遠(yuǎn)征。

      代理類:網(wǎng)易——NetEasy

      Java 代碼

      查看代碼打印?

      在代理類網(wǎng)易中,包含了暴雪的實例對象,網(wǎng)易在實現(xiàn)tbc接口時,加入了自己的邏輯,并執(zhí)行了暴雪實現(xiàn)的方法。

      寫個工廠方法獲取Wow的實例,對客戶隱藏了實現(xiàn),玩家不知道是返回的是暴雪還是網(wǎng)易。

      -

      Java 代碼

      -

      查看代碼打印?

      寫個main函數(shù)測試下

      Java 代碼

      查看代碼打印?

      這就是最簡單的一個靜態(tài)代理的模式,功能就是網(wǎng)易為暴雪代理魔獸世界。

      靜態(tài)代理的缺陷:

      1、如果接口中方法很多,代理類對每個方法都做代理,那么靜態(tài)代理類規(guī)模會非常龐大。

      2、如果接口中增加/減少了一個方法,實現(xiàn)類和代理類都需要做相應(yīng)的修改,牽一發(fā)動全身。

      動態(tài)代理

      Java動態(tài)代理,程序并不難寫,但是想弄懂其中的原理,還是需要仔細(xì)研究jdk源碼的。

      還是以上面的例子說明,魔獸世界Wow這個接口,還有暴雪Blizzard這個實現(xiàn)類,都無須改動。我們增加一個動態(tài)代理處理器和工廠方法。

      Java 代碼

      查看代碼打印?

      DynamicHandler這個類很重要,它實現(xiàn)了InvocationHandler接口。Java中要實現(xiàn)動態(tài)代理,需要實現(xiàn)InvocationHandler這個接口。但是實現(xiàn)InvocationHandler接口的類,并不是動態(tài)代理類,動態(tài)代理類會在運行時生成,jvm在運行時,會根據(jù)實現(xiàn)了InvocationHandler接口的類生成一個動態(tài)代理類。因此有些文章將實現(xiàn)了InvocationHandler接口的類定義為動態(tài)代理類,這個是有欠妥當(dāng)?shù)模鋵嵵皇且粋€handler,真正的動態(tài)代理類是運行時生成的。

      我們看DynamicHandler這個類,它實現(xiàn)了InvocationHandler接口中的invoke方法,invoke方法中植入了自己的邏輯,并用反射的方式對委托類進(jìn)行方法調(diào)用。僅僅看這個實現(xiàn),其實很模糊,這個invoke(Object proxy, Method method, Object[] args)方法在哪里調(diào)用的?

      我么再看下動態(tài)工廠,它會返回動態(tài)代理的實例。同樣,對于客戶而言,并不知道實現(xiàn)Wow接口的是委托類還是代理類。

      Java 代碼

      查看代碼打印?

      看上面的代碼,最關(guān)鍵的莫過于Proxy.newProxyInstance(blizzard.getClass().getClassLoader(), blizzard.getClass().getInterfaces(), invocatioonHandler)這句了。這一句在運行時會創(chuàng)建動態(tài)代理類并返回它的一個實例對象。我們看其源碼實現(xiàn)。Proxy.newProxyInstance(...)源碼較多,我們抽取其中的關(guān)鍵語句

      Java 代碼

      查看代碼打印?

      中間省略了N句,

      (1)Class cl = getProxyClass0(loader, intfs)返回運行時生成的動態(tài)代理類。

      深入剖析java代理模式

      (2)final Constructor cons = cl.getConstructor(constructorParams)返回該代理類的構(gòu)造函數(shù)。

      (3)cons.newInstance(new Object[]{h})則通過構(gòu)造函數(shù)創(chuàng)建代理類的實例對象,注意參數(shù)h就是傳遞的實現(xiàn)InvocationHandler接口的對象實例。

      其中最關(guān)鍵的還是Class cl = getProxyClass0(loader, intfs); ?這句生成了動態(tài)代理類。跟蹤源代碼,最終找到以下語句

      Java 代碼

      查看代碼打印?

      ProxyGenerator.generateProxyClass()完成了生成字節(jié)碼的動作,這個方法可以在運行時產(chǎn)生一個描述代理類字節(jié)碼的byte[]數(shù)組。具體實現(xiàn)這里暫時不深究。

      private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);

      defineClass0則是一個native方法,根據(jù)classloader,字節(jié)碼數(shù)組等動態(tài)生成一個class類。

      我們寫一個main方法,測試一下動態(tài)代理

      Html 代碼

      查看代碼打印?

      由于代理類是動態(tài)生成的,一般來說,并不能找到其class文件。我們加上System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");這句話,這樣可以在磁盤中看到class文件,位于項目根目錄下的com/sun/proxy路徑下,文件名為$Proxy0.class。反編譯一下,看其源碼

      Java 代碼

      查看代碼打印?

      省略了equals, hashcode, toString方法,和tbc()的實現(xiàn)是類似的。

      可以看到$Proxy0這個類繼承了Proxy類并實現(xiàn)了Wow接口。

      由于繼承了Proxy類,因此擁有了InvocationHandler的實現(xiàn)類的實例,上面在DynamicFactory中,我們是通過Proxy.newInstance(......)傳遞了InvocationHandler的實現(xiàn)類實例的。

      $Proxy0中tbc()的實現(xiàn),this.h.invoke(this, m3, null); 其實就是調(diào)用了DynamicHandler中的invoke方法。

      這樣一來,整個流程都串通了,我們終于弄清楚了整個流程。

      總結(jié)

      與靜態(tài)代理相比,動態(tài)代理將接口中的所有方法都通過InvocationHandler的invoke方法處理,比較靈活。

      靜態(tài)代理的那些缺陷,動態(tài)代理基本都能解決。

      從上面的實現(xiàn)中,我們還可以看到AOP的一個雛形。

      Java中自帶的動態(tài)代理也有一定的局限性,它只是針對接口而言的,如果想對class對代理,則必須借助CGLib等開源jar包實現(xiàn)。而且關(guān)于其中的動態(tài)字節(jié)碼等關(guān)鍵技術(shù),還有待深入研究。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:提高軟件開發(fā)性能的方案
      下一篇:系統(tǒng)調(diào)用有哪些類別?如何進(jìn)行?有什么作用?
      相關(guān)文章
      亚洲亚洲人成综合网络| 亚洲福利精品电影在线观看| 日韩亚洲变态另类中文| 亚洲精品国产高清嫩草影院| jjzz亚洲亚洲女人| 亚洲国产成人精品无码久久久久久综合| 亚洲国产精品99久久久久久| 亚洲人成欧美中文字幕| 亚洲丰满熟女一区二区哦| 亚洲精品无码一区二区| 亚洲av无码专区首页| 久久亚洲精品无码av| 日韩亚洲国产综合久久久| 亚洲第一黄色网址| 久久久久亚洲AV成人网人人软件| 久久精品国产亚洲Aⅴ香蕉| 亚洲中久无码永久在线观看同| 亚洲深深色噜噜狠狠爱网站| 亚洲精品V欧洲精品V日韩精品| 国产V亚洲V天堂无码久久久| 亚洲人成网站影音先锋播放| 亚洲色图古典武侠| 亚洲一区二区三区播放在线 | 伊人久久精品亚洲午夜| 亚洲欭美日韩颜射在线二| 亚洲国产第一站精品蜜芽| 久久久久亚洲AV无码网站| 亚洲人成综合在线播放| 亚洲精品久久无码| 亚洲精品NV久久久久久久久久| 国外亚洲成AV人片在线观看| 亚洲国产精品一区二区久久hs| 亚洲一级二级三级不卡| 色偷偷亚洲女人天堂观看欧| 亚洲精品第一国产综合亚AV| 亚洲国产综合人成综合网站| 精品久久久久久亚洲| 亚洲精品国产啊女成拍色拍| 99久久国产亚洲综合精品| 内射无码专区久久亚洲| 亚洲乱码无码永久不卡在线|