摘要:之后通過(guò)類的靜態(tài)方法取得一個(gè)代理類實(shí)例再次鄙視自己。值得一提,動(dòng)態(tài)代理把也代理了。總結(jié)動(dòng)態(tài)代理優(yōu)點(diǎn)相比靜態(tài)代理,不用每代理一個(gè)類就得寫一個(gè)新的代理類。缺點(diǎn)只能代理實(shí)現(xiàn)了接口的類,因?yàn)槭菃卫^承,代理類已經(jīng)是類的子類了。
動(dòng)態(tài)代理
這里暫時(shí)只做JDK動(dòng)態(tài)代理分析。動(dòng)態(tài)代理應(yīng)用廣泛,例如AOP。
吐槽自己一下,設(shè)計(jì)的類,接口名不是很好。。anyway,大致就是這樣。根據(jù)規(guī)范,Mama類實(shí)現(xiàn)InvocationHandler接口,實(shí)現(xiàn)invoke方法。之后通過(guò)Proxy類的靜態(tài)方法newProxyInstance取得一個(gè)代理類實(shí)例eat(再次鄙視自己)。當(dāng)eat.eat()時(shí),調(diào)用了Mama的invoke方法。
很好奇,源碼是如何實(shí)現(xiàn)代理的。值得一提,JDK動(dòng)態(tài)代理把equals(),toString(),hashCode()也代理了。
一路debug發(fā)現(xiàn),最后調(diào)用了Proxy類下內(nèi)部類ProxyClassFactory的apply方法,其中包含的下列代碼最終動(dòng)態(tài)地創(chuàng)建了proxy class 文件
這時(shí)我們反編譯看看,最后編譯成功的proxy class
public final class KidProxy extends Proxy implements Eat { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public KidProxy(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void eat() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)super.h.invoke(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m3 = Class.forName("com.ProxyDemo.Eat").getMethod("eat", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
通過(guò)構(gòu)造函數(shù)KidProxy(InvocationHandler var1)初始化類instance,這個(gè)super(var1)即是Proxy的構(gòu)造函數(shù)Proxy(InvocationHandler invocationHandler)即是靜態(tài)方法newProxyInstance傳過(guò)去的參數(shù)。具體的調(diào)用又是在newProxyInstance方法中的最后一句
return cons.newInstance(new Object[]{h});
可知是通過(guò)反射實(shí)例化proxy對(duì)象的,同樣的在構(gòu)造proxy class文件時(shí),也是通過(guò)反射,通過(guò)其實(shí)現(xiàn)的interfaces的具體方法將需要實(shí)現(xiàn)的method寫入proxy class文件的。在記載class文件時(shí),通過(guò)static構(gòu)建method。
static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m3 = Class.forName("com.ProxyDemo.Eat").getMethod("eat", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }
其中m3就是我要代理的方法。具體調(diào)用的時(shí)候,通過(guò)將方法delegate給invocationHandler實(shí)例。
總結(jié)JDK動(dòng)態(tài)代理
優(yōu)點(diǎn)
相比靜態(tài)代理,不用每代理一個(gè)類就得寫一個(gè)新的代理類。
缺點(diǎn)
只能代理實(shí)現(xiàn)了interface接口的類,因?yàn)閖ava是單繼承,代理類已經(jīng)是Proxy類的子類了。實(shí)現(xiàn)代理沒(méi)有實(shí)現(xiàn)接口的類,還得靠ASM技術(shù)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/70352.html
摘要:這種語(yǔ)法,在中被稱為動(dòng)態(tài)代理。在動(dòng)態(tài)代理機(jī)制中,這個(gè)角色只能是接口。動(dòng)態(tài)代理就是實(shí)現(xiàn)的技術(shù)之一。 所謂動(dòng)態(tài)代理,指的是語(yǔ)言提供的一種語(yǔ)法,能夠?qū)?duì)對(duì)象中不同方法的調(diào)用重定向到一個(gè)統(tǒng)一的處理函數(shù)中來(lái)。python重寫__getattr__函數(shù)能夠做到這一點(diǎn),就連世界上最好的語(yǔ)言也提供稱為魔術(shù)方法的__call。這種語(yǔ)法除了能更好的實(shí)現(xiàn)動(dòng)態(tài)代理外,還是RPC框架實(shí)現(xiàn)原理的一部分。 動(dòng)態(tài)代理...
摘要:動(dòng)態(tài)地代理,可以猜測(cè)一下它的含義,在運(yùn)行時(shí)動(dòng)態(tài)地對(duì)某些東西代理,代理它做了其他事情。所以動(dòng)態(tài)代理的內(nèi)容重點(diǎn)就是這個(gè)。所以下一篇我們來(lái)細(xì)致了解下的到底是怎么使用動(dòng)態(tài)代理的。 之前講了《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》,本來(lái)打算下一篇講講Srping的AOP的,但是其中會(huì)涉及到Java的動(dòng)態(tài)代理,所以先單獨(dú)一篇來(lái)了解下Java的動(dòng)態(tài)代理到底是什么,Java是怎么實(shí)現(xiàn)它的。 ...
摘要:動(dòng)態(tài)代理能干嘛提供了另外一種實(shí)現(xiàn)接口的方式,不用也能實(shí)現(xiàn)接口。有了動(dòng)態(tài)代理,中的網(wǎng)絡(luò)交互部分可以完全寫在框架中,對(duì)用戶來(lái)說(shuō)編程更加方便。 靜態(tài)代理 public class TargetClass{ void method1() } public class ProxyClass{ private TargetClass target; public...
摘要:代理模式代理模式通俗一點(diǎn)的解釋就是在操作一個(gè)對(duì)象和對(duì)象中的方法時(shí),不是直接操作這個(gè)對(duì)象,還是通過(guò)一個(gè)代理對(duì)象來(lái)操作這個(gè)實(shí)際的目標(biāo)對(duì)象。 代理模式: 代理模式通俗一點(diǎn)的解釋就是在操作一個(gè)對(duì)象和對(duì)象中的方法時(shí),不是直接操作這個(gè)對(duì)象,還是通過(guò)一個(gè)代理對(duì)象來(lái)操作這個(gè)實(shí)際的目標(biāo)對(duì)象。應(yīng)用場(chǎng)景一般是需要在執(zhí)行某個(gè)已經(jīng)寫好的方法前后再添加一段邏輯,比如執(zhí)行方法前打印日志,或者在執(zhí)行方法之前和之后打時(shí)...
摘要:動(dòng)態(tài)代理是語(yǔ)言中非常經(jīng)典的一種設(shè)計(jì)模式,也是所有設(shè)計(jì)模式中最難理解的一種。本文將通過(guò)一個(gè)簡(jiǎn)單的例子模擬動(dòng)態(tài)代理實(shí)現(xiàn),讓你徹底明白動(dòng)態(tài)代理設(shè)計(jì)模式的本質(zhì),文章中可能會(huì)涉及到一些你沒(méi)有學(xué)習(xí)過(guò)的知識(shí)點(diǎn)或概念。 動(dòng)態(tài)代理是Java語(yǔ)言中非常經(jīng)典的一種設(shè)計(jì)模式,也是所有設(shè)計(jì)模式中最難理解的一種。本文將通過(guò)一個(gè)簡(jiǎn)單的例子模擬JDK動(dòng)態(tài)代理實(shí)現(xiàn),讓你徹底明白動(dòng)態(tài)代理設(shè)計(jì)模式的本質(zhì),文章中可能會(huì)涉及到...
閱讀 995·2023-04-25 19:35
閱讀 2634·2021-11-22 09:34
閱讀 3679·2021-10-09 09:44
閱讀 1713·2021-09-22 15:25
閱讀 2932·2019-08-29 14:00
閱讀 3372·2019-08-29 11:01
閱讀 2596·2019-08-26 13:26
閱讀 1735·2019-08-23 18:08