JDK和CGLIB生成動(dòng)態(tài)代理類的區(qū)別以及Spring動(dòng)態(tài)代理機(jī)制

關(guān)于動(dòng)態(tài)代理和靜態(tài)代理

當(dāng)一個(gè)對象(客戶端)不能或者不想直接引用另一個(gè)對象(目標(biāo)對象)呀邢,這時(shí)可以應(yīng)用代理模式在這兩者之間構(gòu)建一個(gè)橋梁--代理對象鼠次。
按照代理對象的創(chuàng)建時(shí)期不同滤愕,可以分為兩種

靜態(tài)代理:事先寫好代理對象類,在程序發(fā)布前就已經(jīng)存在了谎僻;
動(dòng)態(tài)代理:應(yīng)用程序發(fā)布后撤逢,通過動(dòng)態(tài)創(chuàng)建代理對象膛锭。

靜態(tài)代理其實(shí)就是一個(gè)典型的代理模式實(shí)現(xiàn),在代理類中包裝一個(gè)被代理對象蚊荣,然后影響被代理對象的行為初狰,比較簡單,代碼就不放了互例。

其中動(dòng)態(tài)代理又可分為:JDK動(dòng)態(tài)代理CGLIB代理奢入。

1.JDK動(dòng)態(tài)代理

此時(shí)代理對象和目標(biāo)對象實(shí)現(xiàn)了相同的接口,目標(biāo)對象作為代理對象的一個(gè)屬性媳叨,具體接口實(shí)現(xiàn)中腥光,可以在調(diào)用目標(biāo)對象相應(yīng)方法前后加上其他業(yè)務(wù)處理邏輯关顷。
代理模式在實(shí)際使用時(shí)需要指定具體的目標(biāo)對象,如果為每個(gè)類都添加一個(gè)代理類的話武福,會(huì)導(dǎo)致類很多议双,同時(shí)如果不知道具體類的話,怎樣實(shí)現(xiàn)代理模式呢捉片?這就引出動(dòng)態(tài)代理平痰。
JDK動(dòng)態(tài)代理只能針對實(shí)現(xiàn)了接口的類生成代理。

具體實(shí)現(xiàn)原理:
1伍纫、通過實(shí)現(xiàn)InvocationHandlet接口創(chuàng)建自己的調(diào)用處理器
2宗雇、通過為Proxy類指定ClassLoader對象和一組interface來創(chuàng)建動(dòng)態(tài)代理
3、通過反射機(jī)制獲取動(dòng)態(tài)代理類的構(gòu)造函數(shù)莹规,其唯一參數(shù)類型就是調(diào)用處理器接口類型
4赔蒲、通過構(gòu)造函數(shù)創(chuàng)建動(dòng)態(tài)代理類實(shí)例,構(gòu)造時(shí)調(diào)用處理器對象作為參數(shù)參入
JDK動(dòng)態(tài)代理是面向接口的代理模式访惜,如果被代理目標(biāo)沒有接口那么Spring也無能為力嘹履,
Spring通過java的反射機(jī)制生產(chǎn)被代理接口的新的匿名實(shí)現(xiàn)類,重寫了其中AOP的增強(qiáng)方法债热。

2.CGLIB代理

CGLIB(CODE GENERLIZE LIBRARY)代理是針對類實(shí)現(xiàn)代理砾嫉,
主要是對指定的類生成一個(gè)子類,覆蓋其中的所有方法窒篱,所以該類或方法不能聲明稱final的焕刮。

CGLib是一個(gè)強(qiáng)大、高性能的Code生產(chǎn)類庫墙杯,可以實(shí)現(xiàn)運(yùn)行期動(dòng)態(tài)擴(kuò)展java類配并,Spring在運(yùn)行期間通過
CGlib繼承要被動(dòng)態(tài)代理的類,重寫父類的方法高镐,實(shí)現(xiàn)AOP面向切面編程溉旋。

JDK動(dòng)態(tài)代理和CGLIB代理生成的區(qū)別

JDK動(dòng)態(tài)代理只能對實(shí)現(xiàn)了接口的類生成代理,而不能針對類 嫉髓。
CGLIB是針對類實(shí)現(xiàn)代理观腊,主要是對指定的類生成一個(gè)子類,覆蓋其中的方法 算行。
因?yàn)槭抢^承梧油,所以該類或方法最好不要聲明成final ,final可以阻止繼承和多態(tài)州邢。

兩者速度對比

JDK動(dòng)態(tài)代理是面向接口儡陨,在創(chuàng)建代理實(shí)現(xiàn)類時(shí)比CGLib要快,創(chuàng)建代理速度快。
CGLib動(dòng)態(tài)代理是通過字節(jié)碼底層繼承要代理類來實(shí)現(xiàn)(如果被代理類被final關(guān)鍵字所修飾骗村,那么抱歉會(huì)失斚油省),在創(chuàng)建代理這一塊沒有JDK動(dòng)態(tài)代理快胚股,但是運(yùn)行速度比JDK動(dòng)態(tài)代理要快渔扎。

PS:

  • final 所修飾的數(shù)據(jù)具有“終態(tài)”的特征,表示“最終的”意思:
  • final 修飾的類不能被繼承信轿。
  • final 修飾的方法不能被子類重寫。
  • final 修飾的變量(成員變量或局部變量)即成為常量残吩,只能賦值一次财忽。
  • final 修飾的成員變量必須在聲明的同時(shí)賦值,如果在聲明的時(shí)候沒有賦值泣侮,那么只有 一次賦值的機(jī)會(huì)即彪,而且只能在構(gòu)造方法中顯式賦值,然后才能使用活尊。
  • final 修飾的局部變量可以只聲明不賦值隶校,然后再進(jìn)行一次性的賦值。

參考代碼

CGLIB:
public Object createProxyObject(Object obj) { 
    this.targetObject = obj; 
    Enhancer enhancer = new Enhancer(); 
    enhancer.setSuperclass(obj.getClass()); 
    enhancer.setCallback(this); 
    Object proxyObj = enhancer.create(); 
    return proxyObj;// 返回代理對象蛹锰,返回的對象其實(shí)就是一個(gè)封裝了“實(shí)現(xiàn)類”的代理類深胳,是實(shí)現(xiàn)類的實(shí)例。 
} 
JDK:
public Object newProxy(Object targetObject) {// 將目標(biāo)對象傳入進(jìn)行代理 
    this.targetObject = targetObject;        //注意這個(gè)方法的參數(shù)铜犬,后面是類實(shí)現(xiàn)的接口
    return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), 
            targetObject.getClass().getInterfaces(), this);// 返回代理對象 
}

在代碼中可以看到舞终,在生成代理類時(shí),傳遞的是實(shí)現(xiàn)類所實(shí)現(xiàn)的接口 targetObject.getClass().getInterfaces()癣猾,所以JDK只能對于接口進(jìn)行做代理敛劝。如果換成類的話,則會(huì)拋java.lang.ClassCastException異常纷宇。
在Spring的源碼中夸盟,可以看到很多生成代理類的代碼。

動(dòng)態(tài)代理的應(yīng)用

AOP(Aspect-OrientedProgramming像捶,面向切面編程)上陕,AOP包括切面(aspect)、通知(advice)作岖、連接點(diǎn)(joinpoint)唆垃,實(shí)現(xiàn)方式就是通過對目標(biāo)對象的代理在連接點(diǎn)前后加入通知,完成統(tǒng)一的切面操作痘儡。
實(shí)現(xiàn)AOP的技術(shù)辕万,主要分為兩大類:
一是采用動(dòng)態(tài)代理技術(shù),利用截取消息的方式,對該消息進(jìn)行裝飾渐尿,以取代原有對象行為的執(zhí)行醉途;
二是采用靜態(tài)織入的方式,引入特定的語法創(chuàng)建“方面”砖茸,從而使得編譯器可以在編譯期間織入有關(guān)“方面”的代碼隘擎。
Spring提供了兩種方式來生成代理對象: JDKProxy和Cglib,具體使用哪種方式生成由AopProxyFactory根據(jù)AdvisedSupport對象的配置來決定凉夯。
默認(rèn)的策略是如果目標(biāo)類是接口货葬,則使用JDK動(dòng)態(tài)代理技術(shù),如果目標(biāo)對象沒有實(shí)現(xiàn)接口劲够,則默認(rèn)會(huì)采用CGLIB代理震桶。
如果目標(biāo)對象實(shí)現(xiàn)了接口,可以強(qiáng)制使用CGLIB實(shí)現(xiàn)代理(添加CGLIB庫征绎,并在spring配置中加入<aop:config proxy-target-class="true"/>)蹲姐。

Spring動(dòng)態(tài)代理機(jī)制:

Spirng的AOP的動(dòng)態(tài)代理實(shí)現(xiàn)機(jī)制也是這兩種:JDK動(dòng)態(tài)代理和CGLib動(dòng)態(tài)代理
一般而言Spring默認(rèn)優(yōu)先使用JDK動(dòng)態(tài)代理技術(shù),只有在被代理類沒有實(shí)現(xiàn)接口時(shí)人柿,才會(huì)選擇使用CGLIB技術(shù)來實(shí)現(xiàn)AOP柴墩。
但是也提供了配置參數(shù)來強(qiáng)制選擇使用 CGLIB 技術(shù),如下:

<aop:config proxy-target-class="true" /> 

proxy-target-class="true" 表示強(qiáng)制使用 CGLIB 技術(shù)來實(shí)現(xiàn)AOP凫岖,因?yàn)镃GLIB是生成子類也就是代理類來實(shí)現(xiàn)的江咳,所以proxy-target-class,表示是否代理目標(biāo)類哥放。
如果寫成<aop:config />扎阶,proxy-target-class配置缺省, 就會(huì)由spring來選擇婶芭,spring優(yōu)先使用JDK動(dòng)態(tài)代理來實(shí)現(xiàn)AOP,只有在被代理類沒有實(shí)現(xiàn)接口時(shí)东臀,才會(huì)選擇使用CGLIB技術(shù)來實(shí)現(xiàn)AOP

參考文章

http://www.cnblogs.com/binyue/p/4519652.html
http://blog.csdn.net/qq1723205668/article/details/56481476

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市犀农,隨后出現(xiàn)的幾起案子惰赋,更是在濱河造成了極大的恐慌,老刑警劉巖呵哨,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赁濒,死亡現(xiàn)場離奇詭異,居然都是意外死亡孟害,警方通過查閱死者的電腦和手機(jī)拒炎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挨务,“玉大人击你,你說我怎么就攤上這事玉组。” “怎么了丁侄?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵惯雳,是天一觀的道長。 經(jīng)常有香客問我鸿摇,道長石景,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任拙吉,我火速辦了婚禮潮孽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筷黔。我一直安慰自己恩商,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布必逆。 她就那樣靜靜地躺著,像睡著了一般揽乱。 火紅的嫁衣襯著肌膚如雪名眉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天凰棉,我揣著相機(jī)與錄音损拢,去河邊找鬼。 笑死撒犀,一個(gè)胖子當(dāng)著我的面吹牛福压,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播或舞,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼荆姆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了映凳?” 一聲冷哼從身側(cè)響起胆筒,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎诈豌,沒想到半個(gè)月后仆救,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡矫渔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年彤蔽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片庙洼。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡顿痪,死狀恐怖镊辕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情员魏,我是刑警寧澤丑蛤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站撕阎,受9級特大地震影響受裹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虏束,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一棉饶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧镇匀,春花似錦照藻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至晰韵,卻和暖如春发乔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背雪猪。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工栏尚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人只恨。 一個(gè)月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓译仗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親官觅。 傳聞我的和親對象是個(gè)殘疾皇子纵菌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)休涤,斷路器产艾,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 0.前言 本文主要想闡述的問題如下:什么動(dòng)態(tài)代理(AOP)以及如何用JDK的Proxy和InvocationHan...
    SYFHEHE閱讀 2,257評論 1 7
  • 轉(zhuǎn)自:http://xiezhaodong.me/2017/03/31/Java-JDK%E4%BB%A3%E7%...
    王帥199207閱讀 1,264評論 1 17
  • 從三月份找實(shí)習(xí)到現(xiàn)在疑故,面了一些公司杠览,掛了不少,但最終還是拿到小米纵势、百度踱阿、阿里管钳、京東、新浪软舌、CVTE才漆、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,184評論 11 349
  • 中心廣場見一大爺摔倒了,我過去問:大爺佛点,我一個(gè)月工資1800醇滥,能扶您起來不? 大爺:小伙子超营,你走吧鸳玩,我再等等,看看...
    小白貓的故事閱讀 226評論 0 0