jdk動(dòng)態(tài)代理與cglib動(dòng)態(tài)代理實(shí)現(xiàn)原理

概述

使用過spring aop的人應(yīng)該都知道擎值,spring是通過動(dòng)態(tài)代理來實(shí)現(xiàn)的逐抑。而動(dòng)態(tài)代理聽過的有jdk的動(dòng)態(tài)代理以及cglib的動(dòng)態(tài)代理鸠儿。究竟這兩種代理方式有什么區(qū)別厕氨,好奇研究了下。

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

這里舉個(gè)簡單的例子田晚,普通人要買票国葬,但是自己買票一般都買不到的贤徒,于是汇四,可以讓黃牛代為買票。

public interface BuyTicket {

    /**
     * 買票
     */
    void buyTicket();

}

普通人買票

public class CommonPerson implements BuyTicket {

    @Override
    public void buyTicket() {
        System.out.println("買到票了序宦!");
    }

}

黃牛代理買票

public class HuangNiu implements InvocationHandler{

    private final CommonPerson target;

    public HuangNiu(CommonPerson target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("黃牛幫忙代購");
        Object res = method.invoke(target, args);
        return res;
    }
}

來買票了

public static void main(String[] args) {
    //需要被代理的類
    CommonPerson commonPerson = new CommonPerson();

    //代理類
    HuangNiu huangNiu = new HuangNiu(commonPerson);

    //生成代理對象
    BuyTicket buyTicket = (BuyTicket) Proxy.newProxyInstance(CommonPerson.class.getClassLoader(), new Class[]{BuyTicket.class}, huangNiu);

    //調(diào)用代理對象的方法
    buyTicket.buyTicket();

}

這個(gè)例子很簡單背苦,需要注意的有幾點(diǎn)
1、被代理的類需要實(shí)現(xiàn)某個(gè)接口行剂,比如這里的CommonPerson類實(shí)現(xiàn)了BuyTicket接口。
2腌巾、代理某個(gè)方法需要實(shí)現(xiàn)InvocationHandler接口
3、通過Proxy.newProxyInstance生成代理對象

所以所有的實(shí)現(xiàn)都在Proxy.newProxyInstance里面了壤躲。
分析下Proxy.newProxyInstance源碼



ProxyClassFactory.apply方法

從上面分析知道备燃,動(dòng)態(tài)代理類的生成,最終是在ProxyClassFactory里實(shí)現(xiàn)的漏麦。這里截取些比較重要的方法


總結(jié)下:
1)生成的類名叫做com.sun.proxy.$Proxy+自增數(shù)字
2)在ProxyGenerator.generateProxyClass里生成字節(jié)碼
3)最后使用類加載器加載生成的類

那么jdk的動(dòng)態(tài)代理究竟幫我們生成了怎么樣的類呢?繼續(xù)跟下ProxyGenerator.generateProxyClass方法
方法有點(diǎn)長撕贞,這里就不列出來了,感興趣的可以看下sun.misc.ProxyGenerator#generateClassFile這個(gè)方法

簡單說明下秧均,生成的字節(jié)碼:
1)添加hashCode、equals目胡、toString方法
2)實(shí)現(xiàn)了接口(比如這里的BuyTicket接口)所有的實(shí)現(xiàn)都代理給了InvocationHandler.invoke方法
3)生成一個(gè)帶有InvocationHandler參數(shù)的構(gòu)造函數(shù)

繪制類圖


使用cglib實(shí)現(xiàn)動(dòng)態(tài)代理

CommonPerson

使用cglib無需聲明一個(gè)接口了

public class CommonPerson {

    public void buyTicket() {
        System.out.println("買到票了链快!");
    }

}

代理類需要實(shí)現(xiàn)MethodInterceptor接口

public class HuangNiu implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("黃牛幫忙代購");
        Object res = methodProxy.invokeSuper(o, objects);
        return res;
    }
}
public static void main(String[] args) {
    HuangNiu huangNiu = new HuangNiu();

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(CommonPerson.class);
    enhancer.setCallback(huangNiu);

    CommonPerson person = (CommonPerson) enhancer.create();
    person.buyTicket();
}

代理類的生成邏輯在Enhancer.create方法里。這里分析的代碼就不在貼出來了巨双。

繪制下生成類圖


和jdk動(dòng)態(tài)代理不一樣的是霉祸,cglib生成的方法會繼承被代理類(jdk動(dòng)態(tài)代理是實(shí)現(xiàn)同一個(gè)接口),然后生成的方法也和jdk的一樣脉执,會調(diào)用MethodInterceptor也就是這里的HuangNiu的intercept方法。

總結(jié)

jdk的動(dòng)態(tài)代理和cglib的動(dòng)態(tài)代理,都是通過運(yùn)行時(shí)動(dòng)態(tài)生成字節(jié)碼的方式來實(shí)現(xiàn)代理的迅细。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茵典,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌彩倚,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件帆离,死亡現(xiàn)場離奇詭異结澄,居然都是意外死亡岸夯,警方通過查閱死者的電腦和手機(jī)们妥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來监婶,“玉大人,你說我怎么就攤上這事惑惶。” “怎么了孕似?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵刮刑,是天一觀的道長喉祭。 經(jīng)常有香客問我雷绢,道長,這世上最難降的妖魔是什么翘紊? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任帆疟,我火速辦了婚禮鹉究,結(jié)果婚禮上踪宠,老公的妹妹穿的比我還像新娘。我一直安慰自己柳琢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布他去。 她就那樣靜靜地躺著倒堕,像睡著了一般灾测。 火紅的嫁衣襯著肌膚如雪涩馆。 梳的紋絲不亂的頭發(fā)上允坚,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天蛾号,我揣著相機(jī)與錄音,去河邊找鬼鲜结。 笑死,一個(gè)胖子當(dāng)著我的面吹牛精刷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怒允,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼勘畔!你這毒婦竟也來了丽惶?” 一聲冷哼從身側(cè)響起炫七,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤钾唬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后奕巍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伍绳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年乍桂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了效床。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡剩檀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沪猴,到底是詐尸還是另有隱情采章,我是刑警寧澤壶辜,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站砸民,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏岭参。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一演侯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秒际,春花似錦、人聲如沸程癌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至中鼠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間援雇,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工惫搏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚕涤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓揖铜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子峦椰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

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