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