版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、JDK動態(tài)代理的底層實現(xiàn)原理動態(tài)代理是許多框架底層實現(xiàn)的基礎(chǔ),比方Spirng的AOP等,其實弄清 楚了動態(tài)代理的實現(xiàn)原理,它就沒那么神奇了,下面就來通過案例和分析JDK 底層源碼來揭秘她的神秘面紗,讓她一絲不掛地呈現(xiàn)在我們面前,邪惡 了 O O O代理模式定義存在一個代理對象,并且這個代理對象持有真實對象的引用,以實現(xiàn)對真實對 象的訪問控制。舉個例子,現(xiàn)在公司一般都有V*,使我們在家也能訪問到公司的內(nèi)網(wǎng)(比方 連接公司的數(shù)據(jù)庫等),實現(xiàn)居家辦公。這里V*相當于一個代理,而公司內(nèi) 網(wǎng)相當于被代理對象,也就是真實對象。我們不能直接訪問公司內(nèi)網(wǎng)(真實對 象),但是我們通過V* (代理對象),輸入身
2、份信息,確認無誤后就可以訪 問到公司內(nèi)網(wǎng)。這就是代理模式的作用一一控制對象的訪問。代理模式的分類靜態(tài)代理該代理對象持有被代理對象的引用,客戶端通過調(diào)用代理對象的方法間接實現(xiàn) 調(diào)用真實對象的方法。代理對象可以在調(diào)用真實對象的方法前面加入一些操 作:比方身份驗證,如果身份驗證沒有通過,那么不能訪問真實對象的方法,否Proxy./7eki/?r(9Ay/77s/7ce(this.getClass().getClassLoader()ztarget.getClass( ).getlnterfaces(),this);看看JDK的底層實現(xiàn):publics etMt io ObjectCla*aljoad
3、rClarstl intrtace#threw tX;*galxgunntxcpxonh = null) throw tww MuXlPanrExcapcionO r生成代理類C1au d gOJryCLAMloada” faces ty Constructor cons = cl.atContFuctr( natch fHfclUchM*thodExcption I throw now Intetfialltror(.towering()/) jtch (Ill XAccBExcepVion ) I tbrow nmr Xnt*malXrxor01;) catch (Instantiatia
4、nKxcepion )(貼出代碼,去掉了異常和判斷public static Object newProxylnstance(ClassLoader loader,Class interfaces,TnvocationHand1er h)throws IllegalArgumentExceptionClass cl = getProxyClass(loader, interfaces);/ Class constructorParams = InvocationHandler. class ;Constructor cons 二 cl.getConstructor (constructorPa
5、rams);return cons, newlnstance(new Object h ); 通過源碼可以知道,生成代理類是通過如下方法實現(xiàn)的:Class cl = getProxyC/assoader, interfaces);再追蹤一下,這個方法里面內(nèi)容很多,但是最關(guān)鍵的就是下面這個方法:byte proxyClassFile = ProxyGeneratox.generateProxyClassproxyName, interfaces);通過這個方法就生成了代理類的字節(jié)碼,只不過調(diào)用完就不存在了。所以我們 看不到它的源碼。我們也可以模擬生成代理類,看看生成的動態(tài)代理類到底是個什么東西通
6、過如下類就可以生成代理類的字節(jié)碼/* *GenerateDynamic*生成代理類字節(jié)碼的類*author: tanggao*date: : 2017-9-27 下午 5:36:54*version 1. 0*/public class GenerateDynamic public static void main(String args) /* People p = new Student ();DynamicProxyHand1er handler = new DynamicProxyHandler();People proxy 二(People) Proxy. newProxylnsta
7、nce(handler. getClassO .getClassLoader(), p. getClass(). getlnterfaces(), handler);proxy. sayBye (/,tanggao,/)產(chǎn)/createProxyClassFile 0;private static void createProxyClassFile() String name = ProxySubject;byte data = ProxyGenerator. generateProxyClass(name, new Class People, class );FileOutputStream
8、 out = null;try (out = new FileOutputStream(name + class);System. out. println(new File(hello) getAbsolutePath();out. write(data); catch (FileNotFoundException e) e. printStackTrace (); catch (lOException e) e. printStackTrace ();finally if (null != out)try out. close (); catch (lOException e) e. pr
9、intStackTrace ();)用反編譯工具查看一下生成的字節(jié)碼,先上代碼,后面再分析:import com. dynamic, test. People;import java. lang. reflect. Invocationllandler;import java. lang, reflect. Method;import java. lang, reflect. Proxy;import java. lang, reflect. UndeclaredThrowableException;public final class ProxySubject extends Proxy i
10、mplements Peopleprivatestatic Method ml;privatestatic Method m3;private static Method m4;private static Method mO;private static Method m2;public ProxySubject(InvocationHandler paramlnvocationHandler) throws(super (paramlnvocationHandler);public final boolean equals(Object paramObject) throws(try(re
11、turn (Boolean)this. h. invoke(this, ml, new Object paramObject ). b ooleanValue();catch (Error|RuntimeException localError)(throw localError;)catch (Throwable localThrowable)(throw new UndeclaredThrowableException(localThrowable);public final void sayBye(String paramString)throws(try(this. h. invoke
12、 (this, m3, new Object paramString ); return;catch (Error|RuntimeException localError)throw localError;catch (Throwable localThrowable)throw new UndeclaredThrowableException(localThrowable);public final void sayllello(String paramString) throws(try(this. h. invoke (this, m4, new Object paramString )
13、; return;catch (Error|RuntimeException localError)throw localError;)catch (Throwable localThrowable)throw new UndeclaredThrowableException(localThrowable);public final int hashCode()throwstryreturn (Integer)this. h. invoke(this, mO, null). intValue();catch (Error|RuntimeException localError)(throw l
14、ocalError;)catch (Throwable localThrowable)(throw new UndeclaredThrowableException(localThrowable);)public final String toStringOthrows(tryreturn (String)this. h. invoke(this, m2, null);)catch (Error|RuntimeException localError)throw localError;)catch (Throwable localThrowable)throw new UndeclaredTh
15、rowableException(localThrowable);statictry(ml 二 Class. forName(zzjava. lang. Object/7). getMethod(zzequalsz,, new Class Class. forName (,zjava. lang. Object) );m3 = Class. forName (zzcom. dynamic, test. People,z). getMethod (z,sayByez/, new Cla ss Class. forName (z,java. lang. String) );m4 = Class.
16、forName (/zcom. dynamic, test. Peoplez,). getMethod(/zsayHello/z, new C lass Class. forName (z,java. lang. String7?) );mO = Class. forName(/zjava. lang. Object). getMethod(/zhashCodez,, new Class 0);m2 二 Class. forName (zz java. lang. Objectz,). getMethod (/ztoString/,, new Class M);return;catch (No
17、SuchMethodException localNoSuchMethodException)throw new NoSuchMethodError(localNoSuchMethodException. getMessage();catch (ClassNotFoundException localClassNotFoundException)(throw new NoClassDefFoundError(localClassNotFoundException. getMessage();)分析過程直接看圖:就是調(diào)用 ProxygvProxyg5tance(thk.gex?xy5Qbx-C
18、(ZzvscauctdUDlIir th SIHpn”s stAtie prlvtU autie pflTU tUUfi privite sutic2U, foul PUaa eauAliiOtct xtaXectJpublicObject mtwFroaylnsVafice(ClotLestiot lodax9Xavocai xmBAfiaia rthrow XllgalAr9uiaantNCpi.i6n Xooi 9 et8:exyCi,itox”.Rti幺go dsRtteSs y,a, d- - J *: 一417.tty iCQut.rucEcx cons * eketCocuitx
19、ucrcor (twtum ccnv.ftew:natanclrww Ob5act11 I h li I OAtcii |3UJiefeMetiiodteweXea |ut*urFAl ffCaM(*)*4|i-w n”“j fdE.tmw*4MF*1 i.ottmuMr*M4Ee4a - 3“l(fā)t|“aj dj田毋unrt*;* cuMt&li;*VtWB4th板h歐里構(gòu)通方法聯(lián)用的用處與播cag |lst pKilir !Uia1 elA Frsryifcject eitoiMis Fruxr glmi” 加平;.kleeallnccjEE nikTmBU 8oc3Errwcm所以可以看到
20、生成的動態(tài)代理類其實跟靜態(tài)代理類還是有區(qū)別的,靜態(tài)代理是 我們直接控制真實對象的方法調(diào)用,而動態(tài)代理是通過調(diào)用處理器的invoke方法來調(diào)用真實對象的方法,而這個invoke方法就是我們自己覆寫的方法 t M I . J Q f thnamcpToxyXarMUar InrAC4*.icniiAnlx Ilirivate l*wop:. phlItfwyiutxdle t (I 7_ ,看 gCleK pev AppSodo。 C:Fvofam Ret U86KM*bAX7Q.OH*mimi0 Q017Q27 下 JQ:Hcillo tangg4o比看由詡?cè)账翨yeBye tanggao啊日聿
21、上面就是靜態(tài)代理的一個實現(xiàn),通過靜態(tài)代理,實現(xiàn)了訪問控制,但是在每個 真實對象方法之前都加入了訪問控制代碼來驗證權(quán)限。如果有很多個方法,那么 要在每個方法調(diào)用前都加入驗證權(quán)限的代碼,這樣非常的不靈活且有大量的重 復代碼,即使把驗證權(quán)限抽象出來做過方法或者類,但是還是得在每個方法前 加一段調(diào)用權(quán)限驗證的代碼,比方,一個客戶端只用其中的一個方法,但是代 理中兩個方法都要加入權(quán)限控制,要滿足其他客戶端的調(diào)用需求,上面接口中 只有兩個方法還好,但是如果有上百個方法那豈不是很臃腫。那么有什么方法 解決了,那就是動態(tài)代理動態(tài)代理動態(tài)的生成代理類,而不用像靜態(tài)代理一樣,在編譯期間進行定義類。動態(tài) 代理更加靈
22、活,不用顯示的在所有方法前面或者后面加入權(quán)限驗證、記錄日志 等操作。動態(tài)代理的實現(xiàn)如下:其中真實對象接口和它的實現(xiàn)跟靜態(tài)代理是一樣的。不同的是代理類的創(chuàng)立,靜態(tài)代理是直接新增一個代理類,而動態(tài)代理那么不 是。動態(tài)代理是通過JDK的Proxy和一個調(diào)用處理器InvocationHandler來 實現(xiàn)的,通過Proxy來生成代理類實例,而這個代理實例通過調(diào)用處理器 InvocationHandler接收不同的參數(shù)靈活調(diào)用真實對象的方法。所以我們需要做的是創(chuàng)立調(diào)用處理器,該調(diào)用處理器必須實現(xiàn)JDK的 InvocationHandler/*DynamicProxyHandler*調(diào)用處理器實現(xiàn)動態(tài)代理
23、必不可少的組件*author: tanggao*date: : 2017-9-27 下午 5:08:49*version 1.0*/public class DynamicProxyHandler implements InvocationHandler private People target;public DynamicProxyHandler() this. target=new Student (); 實例化一個真實對象Overridepublic Object invoke (Object proxy, Method method, Object args)throws Throw
24、able boolean friendFlag=true;Object o=null;if(friendFlag) 權(quán)限驗證通過所有方法的權(quán)限驗證只需要在這里加代碼就行了o = method. invoke(target, args);)System. out. printin (t己錄訪問 日 志);return o;/*通過Proxy動態(tài)生成一個代理實例*return*author:tanggaodate:2017-9-27 下午 4:57:07*return:Object/public Object getProxy() /*Proxy. newProxylnstance(ClassLo
25、ader loader, Class interfaces, In vocationllandler h)方法的第一個參數(shù)的作用就是獲取當前類的類加載器,作用是用來生成類的第二個參數(shù)是獲取真實對象的所有接口獲取所有接口的目的是用來生成代理的,因為代理要實現(xiàn)所有的接口第三個參數(shù)是調(diào)用處理器 這里傳入調(diào)用處理器,是因為生成代理實例需要 調(diào)用處理器為什么需要調(diào)用處理器,因為生成的代理不能直接調(diào)用真實對象的方法,而是通過調(diào)用處理器來調(diào)用真實對象的方法,具體就是通過上面定義的Dynam icProxyHandler 重寫父類 InvocationHand 1 er 的 invoke 方法return Proxy. newProxyInstance(this. getClass(). getClassLoader(), target. getClass(). getlnterfaces(), this );代碼解釋:方法:Proxy.newProxyInstance(ClassLoacler loa
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 媒體行業(yè)內(nèi)容創(chuàng)作授權(quán)合同
- 城市智能交通管理系統(tǒng)建設(shè)合同
- 建材購銷合同簡單范本
- 協(xié)議酒店年度合同
- 標準體育場地租賃合同范文
- 技術(shù)開發(fā)委托合同范本
- 進出口合同的履行
- 員工借調(diào)服務(wù)合同
- 道路交通事故糾紛法律知識一本全-記錄
- 基于膜解剖的腹腔鏡與機器人結(jié)直腸腫瘤手術(shù)學-隨筆
- 醫(yī)院物業(yè)服務(wù)組織機構(gòu)及人員的配備、培訓管理方案
- 外觀判定標準
- 江西上饒市2025屆數(shù)學高二上期末檢測試題含解析
- 腦卒中后吞咽障礙患者進食護理團體標準
- 工行人工智能風控
- 2023風電機組預應(yīng)力混凝土塔筒與基礎(chǔ)結(jié)構(gòu)設(shè)計標準
- 小學語文閱讀教學落實學生核心素養(yǎng)方法的研究-結(jié)題報告
- 一年級的成長歷程
- 2024年南京鐵道職業(yè)技術(shù)學院高職單招(英語/數(shù)學/語文)筆試歷年參考題庫含答案解析
- 正月十五元宵節(jié)介紹課件
- 病毒性肺炎疾病演示課件
評論
0/150
提交評論