Java動(dòng)態(tài)代理講解和示例
Java動(dòng)態(tài)代理是一種在運(yùn)行時(shí)創(chuàng)建代理類(lèi)的機(jī)制,動(dòng)態(tài)代理可以在不修改源代碼的情況下,在運(yùn)行時(shí)為某個(gè)接口動(dòng)態(tài)生成實(shí)現(xiàn)類(lèi),并且可以攔截接口中的方法調(diào)用,從而實(shí)現(xiàn)一些特殊的功能。
Java 動(dòng)態(tài)代理底層原理是基于反射機(jī)制實(shí)現(xiàn)的,其中最重要的是 InvocationHandler 接口,它定義了一個(gè) invoke() 方法,用于實(shí)現(xiàn)對(duì)代理類(lèi)中各個(gè)方法的調(diào)用,在 invoke() 方法中,可以實(shí)現(xiàn)對(duì)真實(shí)角色的調(diào)用,并進(jìn)行擴(kuò)展,實(shí)現(xiàn)動(dòng)態(tài)代理的效果。
動(dòng)態(tài)代理的實(shí)現(xiàn)步驟:
1. 創(chuàng)建一個(gè)實(shí)現(xiàn) InvocationHandler 接口的類(lèi),它必須實(shí)現(xiàn) invoke() 方法;
2. 創(chuàng)建被代理的真實(shí)對(duì)象;
3. 通過(guò) Proxy 類(lèi)的 newProxyInstance() 方法創(chuàng)建代理對(duì)象,它需要參數(shù):
(1)ClassLoader:類(lèi)加載器,它是用于加載代理對(duì)象字節(jié)碼的,和被代理對(duì)象使用相同的類(lèi)加載器;
(2)Class[]:字節(jié)碼數(shù)組,它是用于讓代理對(duì)象和被代理對(duì)象有相同方法;
(3)InvocationHandler:它是調(diào)用處理器,執(zhí)行代理對(duì)象的方法時(shí),會(huì)觸發(fā)該對(duì)象的 invoke() 方法;
4. 通過(guò)代理對(duì)象調(diào)用目標(biāo)方法,實(shí)際上會(huì)轉(zhuǎn)到 invoke() 方法中,在 invoke() 方法中,可以進(jìn)行預(yù)處理、調(diào)用后處理等工作。
反射上一篇文章講過(guò)了,這里就是反射的一個(gè)應(yīng)用,這個(gè)最常見(jiàn)的場(chǎng)景就是給代碼加日志,例如在執(zhí)行某個(gè)函數(shù)前將請(qǐng)求體加入到日志中,執(zhí)行后將結(jié)果加入到日志中。這樣可以在不改變?cè)瓉?lái)代碼的基礎(chǔ)上來(lái)實(shí)現(xiàn)。接下來(lái)就使用上一篇反射的例子繼續(xù)擴(kuò)展。
先寫(xiě)一個(gè)Person的接口:
寫(xiě)他的實(shí)現(xiàn):
然后寫(xiě)動(dòng)態(tài)代理類(lèi):
最后測(cè)試一下:
我們看看結(jié)果在執(zhí)行函數(shù)前后執(zhí)行了其他操作:
SpringAOP其實(shí)原理就類(lèi)似這種。