面試官問 Spring AOP 中兩種代理模式的區(qū)別,我懵逼了

基本介紹

代理模式是一種結(jié)構(gòu)性設計模式搪锣。為對象提供一個替身秋忙,以控制對這個對象的訪問。即通過代理對象訪問目標對象构舟,并允許在將請求提交給對象前后進行一些處理灰追。

被代理的對象可以是遠程對象、創(chuàng)建開銷大的對象或需要安全控制的對象狗超。

代理模式主要有三種不同的形式:

靜態(tài)代理:由程序員創(chuàng)建代理類或特定工具自動生成源代碼再對其編譯弹澎。在程序運行前代理類的 .class 文件就已經(jīng)存在了

動態(tài)代理(JDK 代理、接口代理):在程序運行時運用反射機制動態(tài)創(chuàng)建而成努咐,動態(tài)就是在程序運行時生成的苦蒿,而不是編譯時。

cglib 代理(可以在內(nèi)存動態(tài)的創(chuàng)建對象渗稍,而不是實現(xiàn)接口佩迟,屬于動態(tài)代理的范疇)

問題

為什么要控制對于某個對象的訪問呢?舉個例子:有這樣一個消耗大量系統(tǒng)資源的巨型對象竿屹, 你只是偶爾需要使用它报强, 并非總是需要。


你可以實現(xiàn)延遲初始化:在實際有需要時再創(chuàng)建該對象拱燃。對象的所有客戶端都要執(zhí)行延遲初始代碼秉溉。不幸的是, 這很可能會帶來很多重復代碼碗誉。

在理想情況下召嘶, 我們希望將代碼直接放入對象的類中, 但這并非總是能實現(xiàn):比如類可能是第三方封閉庫的一部分哮缺。

解決方案

代理模式建議新建一個與原服務對象接口相同的代理類弄跌, 然后更新應用以將代理對象傳遞給所有原始對象客戶端。代理類接收到客戶端請求后會創(chuàng)建實際的服務對象尝苇, 并將所有工作委派給它铛只。

代理將自己偽裝成數(shù)據(jù)庫對象, 可在客戶端或?qū)嶋H數(shù)據(jù)庫對象不知情的情況下處理延遲初始化和緩存查詢結(jié)果的工作茎匠。

這有什么好處呢?如果需要在類的主要業(yè)務邏輯前后執(zhí)行一些工作押袍, 你無需修改類就能完成這項工作诵冒。由于代理實現(xiàn)的接口與原類相同, 因此你可將其傳遞給任何一個使用實際服務對象的客戶端谊惭。

代理模式結(jié)構(gòu)

1.服務接口?(Service Interface) 聲明了服務接口汽馋。代理必須遵循該接口才能偽裝成服務對象侮东。

服務?(Service) 類提供了一些實用的業(yè)務邏輯。

代理?(Proxy) 類包含一個指向服務對象的引用成員變量豹芯。代理完成其任務 (例如延遲初始化悄雅、 記錄日志、 訪問控制和緩存等) 后會將請求傳遞給服務對象铁蹈。通常情況下宽闲, 代理會對其服務對象的整個生命周期進行管理。

客戶端?(Client) 能通過同一接口與服務或代理進行交互握牧, 所以你可在一切需要服務對象的代碼中使用代理容诬。

打游戲有代練、買賣房子有中介代理沿腰、再比如一般公司投互聯(lián)網(wǎng)廣告也可以找代理公司览徒,這里的代練、中介颂龙、廣告代理公司扮演的角色都是代理习蓬。

這里舉個更接近程序員的例子,比如有些變態(tài)的公司不允許在公司刷微博措嵌,看視頻躲叼,可以通過一層代理來限制我們訪問這些網(wǎng)站。

廢話不多說铅匹,先來個靜態(tài)代理押赊。

靜態(tài)代理

1、定義網(wǎng)絡接口

2包斑、真正的網(wǎng)絡連接

3流礁、公司的網(wǎng)絡代理

4、客戶端驗證

5罗丰、輸出

不能訪問娛樂性網(wǎng)站神帅,但是可以用 360 搜索,SO 靠譜萌抵,哈哈

靜態(tài)代理類優(yōu)缺點

優(yōu)點:

在不修改目標對象的前提下找御,可以通過代理對象對目標對象功能擴展

代理使客戶端不需要知道實現(xiàn)類是什么,怎么做的绍填,而客戶端只需知道代理即可(解耦合)霎桅,對于如上的客戶端代碼,RealInterner() 可以應用工廠將它隱藏讨永。

缺點:

代理類和委托類實現(xiàn)了相同的接口滔驶,代理類通過委托類實現(xiàn)了相同的方法。這樣就出現(xiàn)了大量的代碼重復卿闹。如果接口增加一個方法揭糕,除了所有實現(xiàn)類需要實現(xiàn)這個方法外萝快,所有代理類也需要實現(xiàn)此方法。增加了代碼維護的復雜度著角。

代理對象只服務于一種類型的對象揪漩,如果要服務多類型的對象。勢必要為每一種對象都進行代理吏口,靜態(tài)代理在程序規(guī)模稍大時就無法勝任了奄容。

動態(tài)代理

靜態(tài)代理會產(chǎn)生很多靜態(tài)類,所以我們要想辦法可以通過一個代理類完成全部的代理功能锨侯,這就引出了動態(tài)代理嫩海。

JDK原生動態(tài)代理

代理對象,不需要實現(xiàn)接口囚痴,但是目標對象要實現(xiàn)接口叁怪,否則不能用動態(tài)代理

代理對象的生成,是通過 JDK 的 API(反射機制)深滚,動態(tài)的在內(nèi)存中構(gòu)建代理對象

在 Java 中要想實現(xiàn)動態(tài)代理機制奕谭,需要

java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 類的支持

Coding

1、網(wǎng)絡接口不變

2痴荐、真正的網(wǎng)絡連接血柳,也不會改變

3、動態(tài)代理生兆,需要實現(xiàn) InvocationHandler难捌,我們用 Lambda 表達式簡化下

4、客戶端

動態(tài)代理的方式中鸦难,所有的函數(shù)調(diào)用最終都會經(jīng)過 invoke 函數(shù)的轉(zhuǎn)發(fā)根吁,因此我們就可以在這里做一些自己想做的操作,比如日志系統(tǒng)合蔽、事務击敌、攔截器、權(quán)限控制等拴事。

cglib代理

靜態(tài)代理和 JDK 代理模式都要求目標對象實現(xiàn)一個接口沃斤,但有時候目標對象只是一個單獨的對象,并沒有實現(xiàn)任何接口刃宵,這個時候就可以使用目標對象子類來實現(xiàn)代理衡瓶,這就是 cglib 代理。

cglib(Code Generation Library)是一個基于ASM的字節(jié)碼生成庫牲证,它允許我們在運行時對字節(jié)碼進行修改和動態(tài)生成哮针。cglib 通過繼承方式實現(xiàn)代理。它廣泛的被許多AOP的框架使用,比如我們的 Spring AOP诚撵。

cglib 包的底層是通過使用字節(jié)碼處理框架 ASM 來轉(zhuǎn)換字節(jié)碼并生成新的類。

cglib 代理也被叫做子類代理键闺,它是在內(nèi)存中構(gòu)建一個子類對象從而實現(xiàn)目標對象功能擴展寿烟。

Coding

添加 cglib 依賴

1、不需要接口

2辛燥、代理工廠類

3筛武、客戶端

4、輸出


代理模式適合應用場景

使用代理模式的方式多種多樣挎塌, 我們來看看最常見的幾種徘六。

延遲初始化 (虛擬代理):如果你有一個偶爾使用的重量級服務對象, 一直保持該對象運行會消耗系統(tǒng)資源時榴都, 可使用代理模式待锈。你無需在程序啟動時就創(chuàng)建該對象, 可將對象的初始化延遲到真正有需要的時候嘴高。

訪問控制 (保護代理):如果你只希望特定客戶端使用服務對象竿音, 這里的對象可以是操作系統(tǒng)中非常重要的部分, 而客戶端則是各種已啟動的程序 (包括惡意程序)拴驮, 此時可使用代理模式春瞬。代理可僅在客戶端憑據(jù)滿足要求時將請求傳遞給服務對象。

本地執(zhí)行遠程服務 (遠程代理):適用于服務對象位于遠程服務器上的情形套啤。在這種情形中宽气, 代理通過網(wǎng)絡傳遞客戶端請求, 負責處理所有與網(wǎng)絡相關(guān)的復雜細節(jié)潜沦。

記錄日志請求 (日志記錄代理):適用于當你需要保存對于服務對象的請求歷史記錄時萄涯。代理可以在向服務傳遞請求前進行記錄。

緩存請求結(jié)果 (緩存代理):適用于需要緩存客戶請求結(jié)果并對緩存生命周期進行管理時止潮, 特別是當返回結(jié)果的體積非常大時窃判。代理可對重復請求所需的相同結(jié)果進行緩存, 還可使用請求參數(shù)作為索引緩存的鍵值喇闸。比如請求圖片袄琳、文件等資源時,先到代理緩存取燃乍,如果沒有就去公網(wǎng)取并緩存到代理服務器

智能引用:可在沒有客戶端使用某個重量級對象時立即銷毀該對象唆樊。代理會將所有獲取了指向服務對象或其結(jié)果的客戶端記錄在案。代理會時不時地遍歷各個客戶端刻蟹, 檢查它們是否仍在運行逗旁。如果相應的客戶端列表為空, 代理就會銷毀該服務對象, 釋放底層系統(tǒng)資源片效。代理還可以記錄客戶端是否修改了服務對象红伦。其他客戶端還可以復用未修改的對象。

AOP 中的代理模式

AOP(面向切面編程)主要的的實現(xiàn)技術(shù)主要有 Spring AOP 和 AspectJ

AspectJ 的底層技術(shù)就是靜態(tài)代理淀衣,用一種 AspectJ 支持的特定語言編寫切面昙读,通過一個命令來編譯,生成一個新的代理類膨桥,該代理類增強了業(yè)務類蛮浑,這是在編譯時增強,相對于下面說的運行時增強只嚣,編譯時增強的性能更好沮稚。(AspectJ 的靜態(tài)代理,不像我們前邊介紹的需要為每一個目標類手動編寫一個代理類册舞,AspectJ 框架可以在編譯時就生成目標類的“代理類”蕴掏,在這里加了個冒號,是因為實際上它并沒有生成一個新的類调鲸,而是把代理邏輯直接編譯到目標類里面了)

Spring AOP 采用的是動態(tài)代理囚似,在運行期間對業(yè)務方法進行增強,所以不會生成新類线得,對于動態(tài)代理技術(shù)饶唤,Spring AOP 提供了對 JDK 動態(tài)代理的支持以及 CGLib 的支持。

默認情況下贯钩,Spring對實現(xiàn)了接口的類使用 JDK Proxy方式募狂,否則的話使用CGLib。不過可以通過配置指定 Spring AOP 都通過 CGLib 來生成代理類角雷。

具體邏輯在

org.springframework.aop.framework.DefaultAopProxyFactory類中祸穷,使用哪種方式生成由AopProxy 根據(jù) AdvisedSupport 對象的配置來決定源碼如下:

具體內(nèi)容就不展開了,后邊整理 SpringAOP 的時候再深入勺三。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末雷滚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吗坚,更是在濱河造成了極大的恐慌祈远,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件商源,死亡現(xiàn)場離奇詭異车份,居然都是意外死亡,警方通過查閱死者的電腦和手機牡彻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門扫沼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事缎除⊙暇停” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵器罐,是天一觀的道長盈蛮。 經(jīng)常有香客問我,道長技矮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任殊轴,我火速辦了婚禮衰倦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旁理。我一直安慰自己樊零,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布孽文。 她就那樣靜靜地躺著驻襟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芋哭。 梳的紋絲不亂的頭發(fā)上沉衣,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音减牺,去河邊找鬼豌习。 笑死,一個胖子當著我的面吹牛拔疚,可吹牛的內(nèi)容都是我干的肥隆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼稚失,長吁一口氣:“原來是場噩夢啊……” “哼栋艳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起句各,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤吸占,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后凿宾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旬昭,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年菌湃,在試婚紗的時候發(fā)現(xiàn)自己被綠了问拘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖骤坐,靈堂內(nèi)的尸體忽然破棺而出绪杏,到底是詐尸還是另有隱情,我是刑警寧澤纽绍,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布蕾久,位于F島的核電站,受9級特大地震影響拌夏,放射性物質(zhì)發(fā)生泄漏僧著。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一障簿、第九天 我趴在偏房一處隱蔽的房頂上張望盹愚。 院中可真熱鬧,春花似錦站故、人聲如沸皆怕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愈腾。三九已至,卻和暖如春岂津,著一層夾襖步出監(jiān)牢的瞬間虱黄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工吮成, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留礁鲁,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓赁豆,卻偏偏與公主長得像仅醇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子魔种,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

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