一文讀懂java動(dòng)態(tài)代理

動(dòng)態(tài)代理的好處

Java動(dòng)態(tài)代理的優(yōu)勢(shì)是實(shí)現(xiàn)無(wú)侵入式的代碼擴(kuò)展哮翘,也就是方法的增強(qiáng);讓你可以在不用修改源碼的情況下仔涩,增強(qiáng)一些方法忍坷;在方法的前后你可以做你任何想做的事情(甚至不去執(zhí)行這個(gè)方法就可以)。此外熔脂,也可以減少代碼量,如果采用靜態(tài)代理柑肴,類(lèi)的方法比較多的時(shí)候霞揉,得手寫(xiě)大量代碼。

動(dòng)態(tài)代理示例:

接口類(lèi):

public?interface?UserService {?

????public?abstract?void?add();

????public?abstract?void?update();

}

接口實(shí)現(xiàn)類(lèi):

public?class?UserServiceImpl?implements?UserService {?


?????public?void?add() {?

????????System.out.println("----- add -----");?

????}


????public?void?update(){

?????????System.out.println("----- update-----");?

????}

}

代理處理類(lèi)MyInvocationHandler.java

import?java.lang.reflect.InvocationHandler;?

import?java.lang.reflect.Method;?

import?java.lang.reflect.Proxy;?


public?class?MyInvocationHandler?implements?InvocationHandler {?


????private?Object target;?


????public?MyInvocationHandler(Object target) {

?//注入目標(biāo)對(duì)象晰骑,方便在invoke中調(diào)用目標(biāo)對(duì)象的目標(biāo)方法

????????super();?

????????this.target = target;?

????}?


????public?Object getProxy() {?

????????return?Proxy.newProxyInstance(Thread.currentThread()?

????????????????.getContextClassLoader(), target.getClass().getInterfaces(),?

????????????????this);?

//指定代理類(lèi)生成時(shí)的加載器适秩,要實(shí)現(xiàn)的接口,代理類(lèi)的代理方法被調(diào)用時(shí)需要調(diào)用哪個(gè)對(duì)象的invoke方法硕舆。

????}?


????@Override?

????public?Object invoke(Object proxy, Method method, Object[] args)?

????????????throws?Throwable {?

//代理類(lèi)的代理方法被調(diào)用時(shí)秽荞,會(huì)調(diào)用傳入的h對(duì)象的invoke方法。

????????System.out.println("----- before -----");?

????????Object result = method.invoke(target, args);?

//調(diào)用真正的目標(biāo)類(lèi)的目標(biāo)方法抚官。

????????System.out.println("----- after -----");?

????????return?result;?

????}?

}?

測(cè)試類(lèi):

public?class?DynamicProxyTest {?


????public?static?void?main(String[] args) {?

????????UserService userService =?new?UserServiceImpl();?

????????MyInvocationHandler invocationHandler =?new?MyInvocationHandler(?

????????????????userService);?


????????UserService proxy = (UserService) invocationHandler.getProxy();?

????????proxy.add();

????????proxy.update();

????}?

}?

輸出:

----- before -----

----- add -----

----- after -----

----- before -----

----- update -----

----- after -----

其基本過(guò)程如下: 1.定義目標(biāo)類(lèi)接口和目標(biāo)類(lèi)? 2.實(shí)現(xiàn)InvocationHandler接口扬跋,在構(gòu)造方法中注入目標(biāo)類(lèi),實(shí)現(xiàn)獲取代理類(lèi)的方法getProxy()?凌节,該方法中調(diào)用Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(),?this);?傳入的類(lèi)加載器用于加載生成的代理類(lèi)的字節(jié)碼(ProxyGenerator.generateProxyClass()的方法是最終生成代理類(lèi)的字節(jié)碼.)钦听,傳入的接口(可以為多個(gè))用于規(guī)定生成的代理類(lèi)需要代理的方法有哪些洒试,傳入的this對(duì)象必須是InvocationHandler的實(shí)現(xiàn)類(lèi)對(duì)象(稱(chēng)為h對(duì)象),因?yàn)樽罱K生成的代理對(duì)象的方法在被調(diào)用是全部是通過(guò)轉(zhuǎn)發(fā)給對(duì)象h的invoke方法來(lái)處理的朴上,你可以在invoke方法中通過(guò)method.invoke(target, args);來(lái)調(diào)用目標(biāo)類(lèi)的方法垒棋,同時(shí)在調(diào)用之前或者之后加入自己的功能代碼。

//重點(diǎn)就是這里痪宰,代理類(lèi)實(shí)現(xiàn)的接口方法

??public?final?void?sayHello(String paramString) {?

????try?{<br>??????//見(jiàn)上面構(gòu)造方法叼架,this.h 就代表MyInvocationHandler類(lèi),所以執(zhí)行的就是我們代理實(shí)現(xiàn)類(lèi)中的invoke方法。

??????this.h.invoke(this, m3,?new?Object[] { paramString });?

??????return;?

????}?

????catch?(Error|RuntimeException localError) {?

??????throw?localError;?

????}?

????catch?(Throwable localThrowable) {?

??????throw?new?UndeclaredThrowableException(localThrowable);?

????}?

??}?

我們可以把 InvocationHandler 看做一個(gè)中介類(lèi)衣撬,中介類(lèi)持有一個(gè)被代理的目標(biāo)對(duì)象碉碉,在 invoke 方法中調(diào)用了目標(biāo)對(duì)象的相應(yīng)方法,而生成的代理類(lèi)中持有中介類(lèi)淮韭,因此垢粮,當(dāng)我們?cè)谡{(diào)用代理類(lèi)的方法的時(shí)候,調(diào)用被轉(zhuǎn)發(fā)到中介類(lèi)h的 invoke 方法靠粪,再轉(zhuǎn)為對(duì)被目標(biāo)對(duì)象的調(diào)用蜡吧。

生成的代理類(lèi):$Proxy0 extends Proxy implements Person,我們看到代理類(lèi)繼承了 Proxy 類(lèi)占键,由于java中的單繼承昔善,所以也就決定了生成的 java 動(dòng)態(tài)代理類(lèi)不能再繼承其它類(lèi),只能對(duì)接口進(jìn)行代理畔乙,所以Java 的動(dòng)態(tài)代理類(lèi)無(wú)法實(shí)現(xiàn)直接針對(duì) 類(lèi)的動(dòng)態(tài)代理君仆,只能通過(guò)接口間接實(shí)現(xiàn)對(duì)類(lèi)的動(dòng)態(tài)代理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末牲距,一起剝皮案震驚了整個(gè)濱河市返咱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌牍鞠,老刑警劉巖咖摹,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異难述,居然都是意外死亡萤晴,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)胁后,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)店读,“玉大人,你說(shuō)我怎么就攤上這事攀芯⊥投希” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)裹纳。 經(jīng)常有香客問(wèn)我择葡,道長(zhǎng),這世上最難降的妖魔是什么剃氧? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任敏储,我火速辦了婚禮,結(jié)果婚禮上朋鞍,老公的妹妹穿的比我還像新娘已添。我一直安慰自己,他們只是感情好滥酥,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布更舞。 她就那樣靜靜地躺著,像睡著了一般坎吻。 火紅的嫁衣襯著肌膚如雪缆蝉。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天瘦真,我揣著相機(jī)與錄音刊头,去河邊找鬼。 笑死诸尽,一個(gè)胖子當(dāng)著我的面吹牛原杂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播您机,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼穿肄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了际看?” 一聲冷哼從身側(cè)響起咸产,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎仿村,沒(méi)想到半個(gè)月后锐朴,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蔼囊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了衣迷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畏鼓。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖壶谒,靈堂內(nèi)的尸體忽然破棺而出云矫,到底是詐尸還是另有隱情,我是刑警寧澤汗菜,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布让禀,位于F島的核電站挑社,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏巡揍。R本人自食惡果不足惜痛阻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望腮敌。 院中可真熱鬧阱当,春花似錦、人聲如沸糜工。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捌木。三九已至油坝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刨裆,已是汗流浹背澈圈。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留崔拥,地道東北人极舔。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像链瓦,于是被迫代替她去往敵國(guó)和親拆魏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容