Java筑基-代理

? 什么是代理火惊?

? 為什么用代理?

? 代理的方式有哪些奔垦?優(yōu)缺點有哪些屹耐?



1、 簡述

代理模式是Java 23種設(shè)計模式之一。代理分為靜態(tài)代理和動態(tài)代理惶岭。所謂代理寿弱,即是通過對其他對象提供代理以控制這個對象訪問。

使用一個代理對象將對象封裝起來按灶,然后使用該代理對象來取代該對象症革。任何對原始對象的調(diào)用都要通過代理,代理對象決定是否以及何時調(diào)用原始對象的方法

1.1 靜態(tài)代理

靜態(tài)代理的實現(xiàn)方式有兩種:a)通過與委托類實現(xiàn)同一接口鸯旁;b)通過繼承委托類噪矛。

這兩種方法正好對應(yīng)動態(tài)代理的兩種方式的實現(xiàn)原理。我們在后續(xù)講解動態(tài)代理的時候铺罢,再詳解該部分艇挨。

1.2 動態(tài)代理

首先,我們 先存在一個疑問韭赘,既然存在靜態(tài)代理了缩滨,為什么又要存在動態(tài)代理呢?首先泉瞻,靜態(tài)代理脉漏,需要開發(fā)人員(程序員)編寫,在運行期間不需要其他消耗袖牙。存在動態(tài)代理鸠删,就是因為如果存在多個委托類,就需要開發(fā)人員手動編寫多個代理類贼陶,這樣就會存在很大的工作量刃泡,那為什么不能由Java自己動態(tài)生成代理類呢,這就是動態(tài)代理存在的理由碉怔。

動態(tài)代理實現(xiàn)的方式也有兩種:a)JDK原生的代理烘贴;b)cglib方式。

所謂動態(tài)代理,即是在運行時自動生成代理類的方式。而靜態(tài)代理類是在編譯期間已然創(chuàng)建肖爵。

1.3 為什么要代理?

當在某個成熟類提供的功能之外锻离,擴展補充功能時,就可以選擇代理模式墓怀。比如:

1)權(quán)限控制汽纠,在某項業(yè)務(wù)類,只有通過安全校驗的用戶才能訪問(調(diào)用)這個類傀履,此時就可以選擇做一個該類的代理類虱朵,要求所有的請求必須通過該代理類,由該代理類做權(quán)限判斷。

2. 代理的用法

簡述中提到碴犬,代理分為動態(tài)代理和靜態(tài)代理絮宁,動態(tài)代理和靜態(tài)代理又分別有兩種用法,那下面我們先講講靜態(tài)代理的用法服协。

2.1 靜態(tài)代理

靜態(tài)代理的第一種用法绍昂,就是與委托類實現(xiàn)同一接口,代理類持有委托類的實例偿荷,實際邏輯還是由委托類完成治专。我們以電影演員(MovieActor)與經(jīng)紀人(Agent)為例。

1) 首先定義一個接口遭顶,Actor


1

2) 定義電影演員類,實現(xiàn)Actor接口


2

3) 定義經(jīng)紀人類(Agent)(即MovieActor的代理類)泪蔫,我們?nèi)∶麨锳ctorProxy.同樣實現(xiàn)Actor類


4) 至此棒旗,靜態(tài)代理的第一種方式我們已經(jīng)編寫完成了,讓我們測試一下吧撩荣。


3


4

第二種方式铣揉,是采用繼承的方式實現(xiàn)的。還是同樣的例子:

1) 定義藝人類Actor


5

2) 定義經(jīng)紀人類ActorProxy餐曹,繼承藝人類(Actor)


6

3) 至此逛拱,第二種方式我們也完成,讓我們測試下吧台猴。


7


8

至此朽合,靜態(tài)代理的兩種方式我們已經(jīng)講解完成。

2.2 動態(tài)代理

動態(tài)代理同樣分為兩種方式饱狂,jdk動態(tài)代理和cglib代理曹步。為什么動態(tài)代理要有兩種方式呢?因為jdk代理的委托類需要實現(xiàn)接口休讳,即jdk代理針對于接口讲婚,若委托類未實現(xiàn)任何接口,則無法使用動態(tài)代理類俊柔。這也是cglib代理存在的理由筹麸,因為cdlib可以針對接口,也可以針對繼承類雏婶,即委托類只要有父類或父接口即可物赶。至于為何jdk只能使用接口方式,我們后續(xù)會分析其原理留晚。

Ok块差,下面我們先開始講解jdk代理。還是同樣的例子

1) 首先我們還是先定義藝人接口 Actor


9

2) 定義電影藝人類 MovieActor,使其實現(xiàn)藝人接口Actor.


10

3) 定義藝人演出代理調(diào)用處理類ActorInvocationHandler,該類需實現(xiàn)jdk的InvocationHandler接口。


11

通過上述截圖憨闰,我們可以看到状蜗,我們在實現(xiàn)InvocationHandler接口,需實現(xiàn)其invoke方法鹉动,該方法有3個參數(shù)轧坎,分別為代理類對象,代理的方法及代理的方法參數(shù)泽示。代理調(diào)用處理器是通過反射實現(xiàn)的缸血。

4) 因為動態(tài)代理類是在運行時自動生成的,那么我們直接來測試吧械筛。


12

上述截圖中捎泻,代理對象是通過jdk的Proxy類生成。我們調(diào)用Proxy類的newProxyInstance方法埋哟,傳參分別為委托類的類加載器笆豁、委托類的父接口數(shù)組及代理的調(diào)用處理器實例。在調(diào)用代理類的方法時赤赊,代理類會將方法調(diào)用傳遞到invoke方法闯狱,運行結(jié)果如下:


13

如果我們再定義TV Actor,同樣采用上述初始化代理類的方式即可抛计。


14


15

那既然是在運行時生成代理類哄孤,我們可以看到生成的代理類嗎?當然可以吹截,只要在初始化代理類之前瘦陈,設(shè)置參數(shù):

sun.misc.ProxyGenerator.saveGeneratedFiles 為 true


16

設(shè)置完成后,會保存代理類波俄,類名為$Proxy+數(shù)字双饥,存儲位置在當前工程目錄下的com/sun目錄下。

我們分析下生成的class文件弟断,看下反編譯后的源碼:

a)可以很直接的看到代理類繼承于Proxy咏花,實現(xiàn)于在Actor(在初始化階段傳入的接口數(shù)組)


17

b)在反編譯后文件中存在4個Method類型的類變量,這里為什么會有4個呢阀趴?不要著急昏翰,后面我們會看下這4個類變量分別代表的什么,就明白了刘急。


18

通過下面的靜態(tài)塊代碼棚菊,我們可以看到m1、m2叔汁、m3统求、m4代表的含義检碗,即從Object繼承來的3個公共方法和從Actor實現(xiàn)的show方法(即我們需要代理的方法)


19

我們詳細的看下show方法是如何實現(xiàn)的


20

通過代碼我們可以,方法的最終實現(xiàn)是調(diào)用的代理調(diào)用處理器的invoke方法

c)繼續(xù)看class文件码邻,存在一個參數(shù)類型為InvocationHandler的構(gòu)造方法折剃,方法內(nèi)部將InvocationHandler參數(shù)傳遞給父類Proxy


21

我們可以看到Proxy類中存在InvocationHandler類型的變量,這個代表的就是我們編寫的代理調(diào)用處理類像屋。


22

5) 我們通過時序圖分析下動態(tài)代理類的生成原理怕犁,時序圖如下(后續(xù)補充):

至此,jdk動態(tài)代理我們已經(jīng)分析完成己莺∽喔Γ可以看出jdk動態(tài)代理和靜態(tài)代理的第一種方式實現(xiàn)方式是一致的。后面我們會繼續(xù)分析cglib動態(tài)代理凌受。cglib代理方式需引入相關(guān)jar包阵子,我們采用maven管理項目工程,可直接在maven 倉庫中搜索相應(yīng)的版本胜蛉。存在父接口和不存在父接口的cglib均可以使用挠进,這是與jdk代理的不同之處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腾么,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子杈湾,更是在濱河造成了極大的恐慌解虱,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漆撞,死亡現(xiàn)場離奇詭異殴泰,居然都是意外死亡,警方通過查閱死者的電腦和手機浮驳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門悍汛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人至会,你說我怎么就攤上這事离咐。” “怎么了奉件?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵宵蛀,是天一觀的道長。 經(jīng)常有香客問我县貌,道長术陶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任煤痕,我火速辦了婚禮梧宫,結(jié)果婚禮上接谨,老公的妹妹穿的比我還像新娘。我一直安慰自己塘匣,他們只是感情好脓豪,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著馆铁,像睡著了一般跑揉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上埠巨,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天历谍,我揣著相機與錄音,去河邊找鬼辣垒。 笑死望侈,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的勋桶。 我是一名探鬼主播脱衙,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼例驹!你這毒婦竟也來了捐韩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鹃锈,失蹤者是張志新(化名)和其女友劉穎荤胁,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屎债,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡仅政,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盆驹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片圆丹。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖躯喇,靈堂內(nèi)的尸體忽然破棺而出辫封,到底是詐尸還是另有隱情,我是刑警寧澤廉丽,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布秸讹,位于F島的核電站,受9級特大地震影響雅倒,放射性物質(zhì)發(fā)生泄漏璃诀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一蔑匣、第九天 我趴在偏房一處隱蔽的房頂上張望劣欢。 院中可真熱鬧棕诵,春花似錦、人聲如沸凿将。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牧抵。三九已至笛匙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間犀变,已是汗流浹背妹孙。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留获枝,地道東北人蠢正。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像省店,于是被迫代替她去往敵國和親嚣崭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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