摘要:如果那個對象在的某個遠端服務(wù)器上直接操作這個對象因為網(wǎng)絡(luò)速度原因可能比較慢那我們可以先用來代替那個對象。這種在運行期直接通過虛擬機加入二進制字節(jié)碼的方法是實現(xiàn)動態(tài)代理的手段
代理的目的到底是什么呢?字面意思上就可以解釋:代理就是“代人理事”,也就是說當(dāng)實現(xiàn)某個操作的時候發(fā)現(xiàn)根本不能使用相關(guān)的對象或者使用這個對象的效果不好的時候就建立一個“代它理事”的代理對象,讓代理對象去完成任務(wù),因為我們關(guān)注的是完成任務(wù)本身,至于是誰完成了這個任務(wù)是不重要的。在這種邏輯下,只要建立的代理對象能夠?qū)崿F(xiàn)像原來那個對象一樣的方法就行,更進一步說,我們新建的這個代理對象有足夠大的自由度,不僅可以完成原來那個對象的功能,還能完成其他我們附加上的功能。
舉兩個例子:
如果那個對象是一個是很大的圖片,需要花費很長時間才能顯示出來,那么當(dāng)這個圖片包含在文檔中時,使用編輯器或瀏覽器打開這個文檔,打開文檔必須很迅速,不能等待大圖片處理完成,這時需要做個圖片Proxy來代替真正的圖片。
如果那個對象在Internet的某個遠端服務(wù)器上,直接操作這個對象因為網(wǎng)絡(luò)速度原因可能比較慢,那我們可以先用Proxy來代替那個對象。
我們來說說靜態(tài)代理和動態(tài)代理:
靜態(tài)代理:我們的代理對象是手動創(chuàng)建的,代理對象內(nèi)部是有一個被代理對象對應(yīng)的類的對象的,所以如果想要執(zhí)行某些被代理對象的方法時就可以使用這個新建的代理對象的同名方法去執(zhí)行,這個時候執(zhí)行的邏輯里面其實就可以用這個內(nèi)部對象的同名方法。
interface Subject{ public void operate(); } class SubjectImpl implements Subject{ @Override public void operate() { System. out.println( "real operate"); } } class SubjProxy implements Subject{ SubjectImpl subjectImpl = new SubjectImpl(); @Override public void operate() { System. out.println( "proxy starts"); subjectImpl.operate(); } } public class TestClass { public static void main(String[] args) { SubjProxy proxy = new SubjProxy(); proxy.operate(); } }
通過上面的例子我們可以看出來新建的代理對象擁有和原對象相同的接口,所以可以像操作原對象一樣地去操作代理對象,代理對象的方法還可以做出拓展,做到原對象做不了的事情。
動態(tài)代理:通過查看靜態(tài)類型的例子,我們有了新的問題:我們其實并想要一個準(zhǔn)確的內(nèi)部對象來完成實際的動作,我們想要的就是原對象的類結(jié)構(gòu),然后通過重寫這個類結(jié)構(gòu)中的相關(guān)方法去直接完成任務(wù),在java中,我們完全可以通過反射去解決這個問題,完全不需要再去在代理對象內(nèi)部搞一個原對象類型的對象出來。
interface Subject{ public void operate(); } class SubjectImpl implements Subject{ @Override public void operate() { System. out.println( "real operate"); } } public class TestClass { public static void main(String[] args) { Subject subject = (Subject)Proxy.newProxyInstance(SubjectImpl. class.getClassLoader(), SubjectImpl.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System. out.println( "Proxy operate"); return null; } }); subject.operate(); } }
動態(tài)代理的方式其實是反射的一種體現(xiàn),為了讓最后的代理對象能夠真的去執(zhí)行被代理的對象才能完成的任務(wù),代理對象必須要得到被代理對象的類的結(jié)構(gòu),這樣就能獲取到被代理對象的方法,截獲這個方法后可以使得方法重定向到代理對象的invoke方法上執(zhí)行被重寫的代理方法。所以新建代理對象實例的時候要將被代理類的類加載器、類實現(xiàn)的接口和重寫被代理類方法的處理器對象作為參數(shù)構(gòu)造代理對象,類加載器用以在后面使用這個代理對象的時候能夠由被代理類的類加載器所加載,類的實現(xiàn)接口用以使得這個代理對象可以對外宣稱自己實現(xiàn)了這些接口,重寫方法的處理器用于真正地重寫那些需要代理的方法,這樣一來我們可以像使用被代理對象一樣去使用代理對象,實現(xiàn)了代理對象能夠真的做到“代人理事”。
interface Subject{ public void operate(); public int func(); } class SubjectImpl implements Subject{ @Override public void operate() { System. out.println( "real operate"); } @Override public int func() { System. out.println( "func"); return 2; } } public class TestClass { public static void main(String[] args) { Subject subject = (Subject)Proxy.newProxyInstance(SubjectImpl. class.getClassLoader(), SubjectImpl.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals( "operate")) System. out.println( "Proxy operate"); else { System. out.println( "func"); return new Integer(1); } return null; } }); subject.operate(); System. out.println(subject.func()); } }
代理模式在虛擬機中的實現(xiàn)其實也不復(fù)雜,在運行期在字節(jié)碼的基礎(chǔ)上新創(chuàng)建一個臨時代理類,臨時代理類的各方法其實就是被代理類的同名方法的反射,執(zhí)行這些方法的時候就會執(zhí)行被代理的類中的反射出的同名方法。這種在運行期直接通過虛擬機加入二進制字節(jié)碼的方法是實現(xiàn)動態(tài)代理的手段:
public final class $Proxy0 extends java.lang.reflect.Proxy implements Subject{ public $Proxy0(java.lang.reflect.InvocationHandler) throws ; public final int func() throws ; public final boolean equals(java.lang.Object) throws ; public final int hashCode() throws ; public final void operate() throws ; public final java.lang.String toString() throws ; static {} throws ; }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/64692.html
摘要:受知乎文章和設(shè)計模式之禪的啟發(fā),我也來搞一篇腦洞小開的文章由標(biāo)題可知,這篇文章是寫給我女朋友看的。于是這就讓經(jīng)紀(jì)人對粉絲說只有萬,我才會寫代碼。 前言 只有光頭才能變強 回顧前面: ThreadLocal就是這么簡單 多線程三分鐘就可以入個門了! 多線程基礎(chǔ)必要知識點!看了學(xué)習(xí)多線程事半功倍 Java鎖機制了解一下 AQS簡簡單單過一遍 Lock鎖子類了解一下 線程池你真不來了解一下...
Java的三種代理模式 參考:http://www.cnblogs.com/cenyu/...Java核心技術(shù)原書第九版6.5節(jié) 為什么使用代理 我們在寫一個功能函數(shù)時,經(jīng)常需要在其中寫入與功能不是直接相關(guān)但很有必要的代 碼,如日志記錄,信息發(fā)送,安全和事務(wù)支持等,這些枝節(jié)性代碼雖然是必要的,但它會帶來以下麻煩: 枝節(jié)性代碼游離在功能性代碼之外,它不是函數(shù)的目的,這是對OO是一種破壞 枝節(jié)性...
摘要:中的詳解必修個多線程問題總結(jié)個多線程問題總結(jié)有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升有哪些源代碼看了后讓你收獲很多,代碼思維和能力有較大的提升開源的運行原理從虛擬機工作流程看運行原理。 自己實現(xiàn)集合框架 (三): 單鏈表的實現(xiàn) 自己實現(xiàn)集合框架 (三): 單鏈表的實現(xiàn) 基于 POI 封裝 ExcelUtil 精簡的 Excel 導(dǎo)入導(dǎo)出 由于 poi 本身只是針對于 ...
摘要:設(shè)計模式之代理模式今天學(xué)到的動態(tài)代理實現(xiàn),對代理這個概念很模糊,看了一篇文章發(fā)現(xiàn)這是一種設(shè)計模式,于是學(xué)習(xí)記錄一下。簡介代理模式是一種對象結(jié)構(gòu)型的模式,主要為其他對象提供一種代理以控制對這個對象的訪問。下面依次講解著三種代理。 設(shè)計模式之代理模式 今天學(xué)到Spring的動態(tài)代理實現(xiàn)AOP,對代理這個概念很模糊,看了一篇文章發(fā)現(xiàn)這是一種設(shè)計模式,于是學(xué)習(xí)記錄一下。 簡介 代理模式是一種對...
摘要:結(jié)構(gòu)型模式適配器模式橋接模式裝飾模式組合模式外觀模式享元模式代理模式。行為型模式模版方法模式命令模式迭代器模式觀察者模式中介者模式備忘錄模式解釋器模式模式狀態(tài)模式策略模式職責(zé)鏈模式責(zé)任鏈模式訪問者模式。 主要版本 更新時間 備注 v1.0 2015-08-01 首次發(fā)布 v1.1 2018-03-12 增加新技術(shù)知識、完善知識體系 v2.0 2019-02-19 結(jié)構(gòu)...
閱讀 824·2019-08-29 16:32
閱讀 904·2019-08-29 12:31
閱讀 3301·2019-08-26 18:26
閱讀 3233·2019-08-26 12:20
閱讀 1791·2019-08-26 12:00
閱讀 3071·2019-08-26 10:58
閱讀 2884·2019-08-23 17:08
閱讀 2363·2019-08-23 16:32