1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試官:策略模式和代理模式有什么區(qū)別?

        共 19615字,需瀏覽 40分鐘

         ·

        2022-05-15 21:26

        大家好,我是田哥,昨天一哥們面試被問到代理模式,剛好,我也正在寫MyBatis源碼分析:小白系列》專欄中的代理模式。

        這里也說明一下,本文是MyBatis源碼分析專欄中的一篇文章。

        感興趣的可以掃描了解一下我的MyBatis源碼分析:小白系列》

        本文目錄:

        兩個(gè)有趣故事

        老田買火車票

        買火車票已經(jīng)是很老的話題了。老田以前每年都會坐綠皮車回家過年,幸運(yùn)的是這兩年老家市區(qū)也有高鐵了,少了些許奔波?,F(xiàn)在就來回憶下當(dāng)年的情景:每到年底最頭疼的就是搶火車票,每次都需要去火車站排隊(duì)買票。因?yàn)橹灰W(wǎng)上的票一開始出售,基本上都是手慢無,最后就只能在周末時(shí)去火車站買票了。但是,有一次無意間聽說黃牛可以幫忙買票,只是要付點(diǎn)手續(xù)費(fèi)。于是,后面每當(dāng)自己搶不到票時(shí),都會走黃牛,費(fèi)用也不是很高。相比自己苦逼到火車站買票,還是輕松很多的。

        ok,故事就講到這里,下面再使用java代碼來實(shí)現(xiàn)。

        未知黃牛黨之前

        //火車站
        public?interface?TrainStationService?{
        ????//坐公交去火車站
        ????void?byBus();
        ????//排隊(duì)買票
        ????void?lineUp();
        ????/**
        ?????*?買票
        ?????*?@param?idCard??身份證
        ?????*?@param?address?去往地址
        ?????*?@param?date????日期
        ?????*/

        ????void?buy(String?idCard,?String?address,?String?date);
        }
        //綠皮車站(老火車站)
        public?class?GreenSkinTrainStationServiceImpl?implements?TrainStationService?{

        ????@Override
        ????public?void?byBus()?{
        ????????System.out.println("坐公交去火車站");
        ????}

        ????@Override
        ????public?void?lineUp()?{
        ????????System.out.println("在火車站苦逼的排隊(duì)中....");
        ????}

        ????@Override
        ????public?void?buy(String?idCard,?String?address,?String?date)?{
        ????????System.out.println(idCard?+?"買到了一張通往"?+?address?+?"的綠皮車票,乘坐日期:"?+?date);
        ????}
        }
        //Client可以理解為老田
        public?class?Client?{
        ????public?static?void?main(String[]?args)?{
        ????????TrainStationService?trainStationService?=?new?GreenSkinTrainStationServiceImpl();
        ????????trainStationService.byBus();
        ????????trainStationService.lineUp();
        ????????trainStationService.buy("423268199901011234",?"老家",?"2019年2月1日");
        ????}
        }

        經(jīng)過一系列的折騰,老田的結(jié)果:

        坐公交去火車站 在火車站苦逼的排隊(duì)中.... 423268199901011234 買到了一張通往老家的綠皮車票,乘坐日期:2019年2月1日

        知道黃牛黨以后

        //黃牛黨
        public?class?CattlePerson?implements?TrainStationService{
        ????private?TrainStationService?trainStationService;

        ????public?CattlePerson()?{
        ????????this.trainStationService?=?=?new?GreenSkinTrainStationServiceImpl();
        ????}

        ????@Override
        ????public?void?byBus()?{
        ????????trainStationService.byBus();
        ????}
        ????@Override
        ????public?void?buy(String?idCard,?String?address,?String?date)?{
        ????????System.out.println("收手續(xù)費(fèi)");
        ????????this.byBus();
        ????????this.lineUp();
        ????????trainStationService.buy(idCard,?address,?date);
        ????????System.out.println("黃牛黨把買到的票給老田");
        ????}
        ????@Override
        ????public?void?lineUp()?{
        ????????trainStationService.lineUp();
        ????}

        }
        //Client可以理解為老田
        public?class?Client?{
        ????public?static?void?main(String[]?args)?{
        ????????CattlePerson?cattlePerson=new?CattlePerson();
        ????????cattlePerson.buy("423268199901011234",?"老家",?"2019年2月1日");
        ????}
        }

        最后老田買車票結(jié)果是這樣的:

        黃牛黨收手續(xù)費(fèi) 坐公交去火車站 在火車站苦逼的排隊(duì)中.... 423268199901011234 買到了一張通往老家的綠皮車票,乘坐日期:2019年2月1日 黃牛黨把買到的票給老田

        最終老田還是搞到票了,但是不用折騰自己了。

        老田玩王者農(nóng)藥

        盡管前兩年,乃至現(xiàn)在王者榮耀還是挺火的。也許有的人沒玩過,但是你絕對見過別人玩過。民間傳說“玩Dato的看不起玩英雄聯(lián)盟的,然而玩英雄聯(lián)盟的看不起玩王者榮耀”。哈哈哈,笑笑就可以了,管那么多,自己開心就好。這兩個(gè)游戲本人都玩過,但是沒有很投入。

        但是去年在同事老王的帶領(lǐng)下搞起了王者榮耀,瘋狂的時(shí)候可以玩通宵,大號不能玩了玩小號,小號不行就換 QQ 號......一直想上王者,悲哀的是一直沒上,記得最瘋狂的時(shí)候還是到了差一顆星就到星耀二,但是始終是上不了王者。無意間看到一個(gè)牛逼的玩家,說給他 388 塊就能上王者,才發(fā)現(xiàn)原來可以找人代打的,后面我細(xì)爬了一下,更恐怖的是有專門代打游戲的公司。由此可知,或許很多王者都是別人帶著或者代打上去的吧。

        下面用java來實(shí)現(xiàn)上面的兩種常見:

        老田玩王者農(nóng)藥

        public?interface?PlayerService?{
        ????//登錄
        ????void?login();
        ????//挑戰(zhàn)排位賽
        ????void?challenge();
        ????//升級
        ????void?upgrade();
        }
        public?class?PlayerServiceImpl?implements?PlayerService?{
        ????private?String?userName;
        ????private?String?password;

        ????public?PlayerServiceImpl(String?userName,?String?password)?{
        ????????this.userName?=?userName;
        ????????this.password?=?password;
        ????}

        ????@Override
        ????public?void?login()?{
        ????????//校驗(yàn)用戶名和密碼
        ????????System.out.println("用戶:"?+?this.userName?+?",密碼:"?+?this.password);
        ????????System.out.println(this.userName?+?"登錄了");
        ????}

        ????@Override
        ????public?void?challenge()?{
        ????????System.out.println("挑戰(zhàn)排位賽比賽中...");
        ????}

        ????@Override
        ????public?void?upgrade()?{
        ????????System.out.println(this.userName?+?"又升級了");
        ????}
        }

        //Client當(dāng)做老田
        public?class?Client{
        ????public?static?void?main(String[]?args)?{
        ????????PlayerService?playerService?=?new?PlayerServiceImpl("老田",?"123456");
        ????????playerService.login();
        ????????playerService.challenge();
        ????????playerService.upgrade();
        ????}
        }

        老田玩王者農(nóng)藥情況:

        用戶:老田,密碼:123456 老田登錄了 挑戰(zhàn)排位賽比賽中... 老田又升級了

        老田找人代打上王者

        也是要使用老田的賬號登錄,也是要一場一場的排位,最后達(dá)上王者。不知道能代打游戲之前老田是自己傻傻的一場一場打的。

        //替人打游戲的人或公司
        public?class?PlayerProxy?implements?PlayerService?{
        ????private?PlayerService?playerService;
        ????/**
        ?????*?費(fèi)用
        ?????*/

        ????private?BigDecimal?fee;
        ????private?String?userName;
        ????private?String?password;

        ????public?PlayerProxy(String?userName,?String?password,?BigDecimal?fee)?{
        ????????this.playerService?=?new?PlayerServiceImpl(userName,?password);
        ????????this.fee?=?fee;
        ????????this.userName?=?userName;
        ????????this.password?=?password;
        ????}

        ????@Override
        ????public?void?login()?{
        ????????playerService.login();
        ????}

        ????@Override
        ????public?void?player()?{
        ????????System.out.println("代理商賺取手續(xù)費(fèi)"?+?fee);
        ????????this.login();
        ????????playerService.player();
        ????????this.upgrade();
        ????}

        ????@Override
        ????public?void?upgrade()?{
        ????????playerService.upgrade();
        ????}
        }
        //老王
        public?class?Client?{
        ????public?static?void?main(String[]?args)?{
        ????????//告訴代理商或者代打的人賬戶名+密碼+費(fèi)用
        ????????PlayerProxy?playerProxy?=?new?PlayerProxy("老田",?"123456",?BigDecimal.valueOf(100));
        ????????playerProxy.player();
        ????}
        }

        最后老田只要等著別人給他打好上王者。

        代理商收手續(xù)費(fèi)100 用戶:老田,密碼:123456 老田登錄了 挑戰(zhàn)排位賽比賽中... 老田滿五星升級

        上面兩個(gè)故事中分別有兩個(gè)很重要的角色:黃牛黨和代打游戲的人。

        有黃牛黨后老田不用關(guān)心票是怎么買的、有了代打游戲的人以后老田也不用關(guān)系是怎么上王者的,都全權(quán)交給他們?nèi)ジ伞?/p>

        同樣的生活中的例子:相親找媒婆,租房子找中介等,都是中間有個(gè)代你辦事干活的人。

        以上舉的例子就是傳說中的代理模式。

        代理模式的定義

        Provide?a?surrogate?or?placeholder?for?another?object?to?control?access?to?it.

        代理模式就是由于某些原因需要給某對象提供一個(gè)代理以控制對該對象的訪問。這時(shí),訪問對象不適合或者不能直接引用目標(biāo)對象,代理對象作為訪問對象和目標(biāo)對象之間的中介。

        代理模式是GOF的23種設(shè)計(jì)模式之一(結(jié)構(gòu)型模式)。

        代理模式也叫委托模式,它是一種基本設(shè)計(jì)技巧,許多其他的設(shè)計(jì)模式,比如:狀態(tài)模式,策略模式,訪問者模式本質(zhì)上是在更特殊的場合采用了委托模式。

        角色

        Subject:抽象主題,抽象主題類可以是抽象類也可以是接口,是一個(gè)最普通的業(yè)務(wù)類型定義,沒有特殊要求。

        RealSubject:真實(shí)主題,也叫被委托角色,被代理角色。他是業(yè)務(wù)邏輯的具體執(zhí)行者。

        Proxy:代理,也叫委托類,代理類。它負(fù)責(zé)對真實(shí)角色的應(yīng)用,把所有抽象主題定義的方法限制委托給真實(shí)主題去實(shí)現(xiàn),并且在真實(shí)主題角色處理完畢的前后做預(yù)處理和善后處理工作。

        通用UML

        通用java代碼

        以上三個(gè)角色的java代碼實(shí)現(xiàn)

        public?interface?Subject?{
        ????void?request();
        }
        public?class?RealSbject?implements?Subject?{
        ????@Override
        ????public?void?request()?{
        ??????System.out.println("訪問具體主題角色方法...");
        ????}
        }
        public?class?Proxy?implements?Subject?{
        ????private?RealSubject?realSubject;

        ????public?Proxy()?{
        ????????this.realSubject?=?new?RealSubject();
        ????}

        ????@Override
        ????public?void?request()?{
        ????????preRequest();
        ????????realSubject.request();
        ????????postRequest();
        ????}

        ????public?void?preRequest()?{
        ????????System.out.println("訪問真實(shí)主題之前的預(yù)處理。");
        ????}

        ????public?void?postRequest()?{
        ????????System.out.println("訪問真實(shí)主題之后的后續(xù)處理。");
        ????}
        }
        public?class?ProxyClient?{
        ????public?static?void?main(String[]?args)?{
        ????????Proxy?proxy=new?Proxy();
        ????????proxy.request();
        ????}
        }

        運(yùn)行結(jié)果:

        訪問真實(shí)主題之前的預(yù)處理。訪問具體主題角色方法... 訪問真實(shí)主題之后的后續(xù)處理。

        優(yōu)缺點(diǎn)

        優(yōu)點(diǎn):效率高,只要獲取代理對象并執(zhí)行就結(jié)束了

        缺點(diǎn):如果接口增加新方法,被代理類得改,代理也得改;每一個(gè)被代理類都得有一個(gè)代理類。如果系統(tǒng)很大,那么關(guān)于代理類的維護(hù)的代價(jià)是很大的。

        裝飾器模式

        裝飾器模式是結(jié)構(gòu)性模式之一,裝飾模式指的是在不必改變原類文件和使用繼承的情況下,動態(tài)地?cái)U(kuò)展一個(gè)對象的功能。它是通過創(chuàng)建一個(gè)包裝對象,也就是裝飾來包裹真實(shí)的對象。也可以稱之為包裝模式

        特點(diǎn):動態(tài)添加或者覆蓋被裝飾的接口/抽象類行為。

        關(guān)系:裝飾者和被裝飾者有著接口/抽象類層次關(guān)系。

        角色

        抽象組件(Component)角色:定義一個(gè)將要接收附加責(zé)任的類,即繼承該抽象類的類都有了裝飾和被裝飾的能力。

        具體組件(ConcreteComponent)角色:可以被動態(tài)加上新行為,被裝飾者修飾的類。

        裝飾者(Decorator)角色:裝飾者抽象類,繼承該類都具有裝飾者的能力。

        具體裝飾者(ConcreteDecorator)角色:為具體組件添加新行為。

        通用UML圖

        通用java代碼

        //抽象構(gòu)件
        public?abstract?class?Component?{
        ????public?abstract?void?operate();
        }
        //具體構(gòu)件(最終被裝飾的類)
        public?class?ConcreteComponent?extends?Component?{
        ????@Override
        ????public?void?operate()?{
        ????????System.out.println("doSomething");
        ????}
        }
        //抽象裝飾者
        public?class?Decorator?extends?Component?{
        ????private?Component?component;
        ????//通過構(gòu)造函數(shù)傳遞被裝飾者
        ????public?Decorator(Component?component)?{
        ????????this.component?=?component;
        ????}
        ????//委托給被裝飾者執(zhí)行
        ????@Override
        ????public?void?operate()?{
        ????????this.component.operate();
        ????}
        }
        //具體裝飾類
        public?class?ConcreteDecorator?extends?Decorator?{
        ????//定義被裝飾者
        ????public?ConcreteDecorator(Component?component)?{
        ????????super(component);
        ????}

        ????private?void?before()?{
        ????????System.out.println("在調(diào)用operate方法前給你添加點(diǎn)東西");
        ????}

        ????@Override
        ????public?void?operate()?{
        ????????//調(diào)用前就行裝飾
        ????????this.before();
        ????????//調(diào)用具體被裝飾類的方法
        ????????super.operate();
        ????????//調(diào)用后進(jìn)行裝飾
        ????????this.after();
        ????}

        ????private?void?after()?{
        ????????System.out.println("在調(diào)用operate方法后給你添加點(diǎn)東西");
        ????}
        }
        //測試
        public?class?Client?{
        ????public?static?void?main(String[]?args)?{
        ????????Component?component?=?new?ConcreteComponent();
        ????????Decorator?decorator?=?new?ConcreteDecorator(component);
        ????????decorator.operate();
        ????}
        }

        運(yùn)行結(jié)果:

        在調(diào)用operate方法前給你添加點(diǎn)東西 doSomething 在調(diào)用operate方法后給你添加點(diǎn)東西

        demo 案例

        簡單支付場景,請看代碼實(shí)現(xiàn)

        public?interface?PayService?{
        ????//支付
        ????void?pay();
        }
        //被裝飾的類--支付場景
        public?class?PayServiceImpl?implements?PayService?{
        ????@Override
        ????public?void?pay()?{
        ????????System.out.println("執(zhí)行PayServiceImpl--的--支付--支付方法");
        ????}
        }
        public?interface?PayParamsMsgService?extends?PayService?{
        ????//支付
        ????@Override
        ????void?pay();
        ????//發(fā)站內(nèi)信
        ????void?sendMsg();
        ????//參數(shù)校驗(yàn)
        ????void?checkParams();
        }
        //裝飾類
        public?class?PayParamsMsgServiceImpl?implements?PayParamsMsgService?{
        ????private?PayService?payService;

        ????public?PayParamsMsgServiceImpl(PayService?payService)?{
        ????????this.payService?=?payService;
        ????}
        ????//沒有被裝飾的支付=支付
        ????//裝飾后的支付=支付前進(jìn)行參數(shù)校驗(yàn)-->支付-->支付后發(fā)生信息
        ????@Override
        ????public?void?pay()?{
        ????????checkParams();
        ????????payService.pay();
        ????????sendMsg();
        ????}
        ????@Override
        ????public?void?sendMsg()?{
        ????????System.out.println("發(fā)送支付成功站內(nèi)信");
        ????}
        ????@Override
        ????public?void?checkParams()?{
        ????????System.out.println("校驗(yàn)余額是否足夠,校驗(yàn)密碼是否非法登錄等");
        ????}
        }
        public?class?DemoClient?{
        ????public?static?void?main(String[]?args)?{
        ????????PayService?payService=new?PayServiceImpl();
        ????????PayService?payService1=new?PayParamsMsgServiceImpl(payService);
        ????????payService1.pay();
        ????}
        }

        運(yùn)行結(jié)果:

        校驗(yàn)余額是否足夠,校驗(yàn)密碼是否非法登錄等 執(zhí)行PayServiceImpl--的--支付--支付方法 發(fā)送支付成功站內(nèi)信

        優(yōu)缺點(diǎn)

        優(yōu)點(diǎn)

        • 裝飾類和被裝飾類可以獨(dú)立發(fā)展,而不會相互耦合。說明白了就是Component類無須知道Decorator類,Decorator類是從外部來擴(kuò)展Component,而Decorator也不知道具體的構(gòu)件。
        • 裝飾模式是繼承關(guān)系的一種替代方案。咱們看裝飾類,不管裝飾多少層,返回的對象還是Component,實(shí)現(xiàn)的還是is-a的關(guān)系。
        • 裝飾模式可以動態(tài)擴(kuò)展一個(gè)實(shí)現(xiàn)類的功能,這不需多說,裝飾模式定義就是這么講的。

        缺點(diǎn):多層裝飾比較復(fù)雜。

        使用場景

        1、擴(kuò)展一個(gè)類的功能

        2、動態(tài)增加功能,動態(tài)撤銷。

        開發(fā)過程中,一般是針對老系統(tǒng)或者已經(jīng)正常使用的功能之外添加一些新的功能。不建議新系統(tǒng)使用裝飾器設(shè)計(jì)模式。

        代理模式 VS 裝飾器模式

        這兩個(gè)模式在實(shí)現(xiàn)上很容易陷入難分難解的地步,但是請記住他們的本質(zhì)區(qū)別:裝飾模式重在裝飾、增強(qiáng),而代理模式重在訪問的權(quán)限控制。

        如果你寫了一個(gè)方法,后續(xù)考慮要給這個(gè)方法添加一些功能,可以選擇裝飾模式。如果你寫了一堆方法,后續(xù)考慮統(tǒng)一給這些方法添加功能(比如日志記錄,資源回收),可以選擇代理模式。

        靜態(tài)代理

        字面意義就是靜態(tài)的代理模式,在上面的幾個(gè)代理模式案例中,所有的代理類都是咱們自己手寫的,所以是已經(jīng)定好的,也就可以理解為是死的、靜態(tài)的,由此可知上面案例都是靜態(tài)代理模式。

        定義:由程序員創(chuàng)建或工具生成代理類的源碼,再編譯代理類。所謂靜態(tài)也就是在程序運(yùn)行前就已經(jīng)存在代理類的字節(jié)碼文件,代理類和委托類的關(guān)系在運(yùn)行前就確定了。

        代理模式就是靜態(tài)代理模式。就是被代理對象和代理類都要實(shí)現(xiàn)同一個(gè)接口。

        既然有靜態(tài)代理,不妨假設(shè)一下,這個(gè)代理不需要咱們來寫,那豈不就是動態(tài)代理嗎?

        動態(tài)代理

        何為動態(tài)代理?

        動態(tài)代理是在實(shí)現(xiàn)階段不用關(guān)心代理誰,而是在運(yùn)行階段才指定代理哪一個(gè)對象。上面得案例中的代理類必須是自己創(chuàng)建的,人都知道偷懶,所以完全不想寫那么多代碼了(代理類),所以得動態(tài)生成。JDK動態(tài)代理能解決這個(gè)問題;

        JDK動態(tài)代理

        JDK動態(tài)代理是一種代理模式實(shí)現(xiàn)之一,只能代理接口。

        通用java代碼實(shí)現(xiàn)
        //第一步
        public?interface?Subject?{
        ????void?request();
        }
        //第二步
        public?class?RealSubject?implements?Subject?{
        ????@Override
        ????public?void?request()?{
        ????????System.out.println("訪問具體主題角色方法...");
        ????}
        }
        //第三步
        public?class?JDKDynamicProxy?implements?InvocationHandler?{
        ????/**
        ?????*?將目標(biāo)對象傳入進(jìn)行代理
        ?????*/

        ????private?Object?target;

        ????public?JDKDynamicProxy(Object?target)?{
        ????????this.target?=?target;
        ????}

        ????/**
        ?????*?獲取被代理接口實(shí)例對象
        ?????*/

        ????public??T?getProxy()?{
        ????????return?(T)?Proxy.newProxyInstance(target.getClass().getClassLoader(),?target.getClass().getInterfaces(),?this);
        ????}
        ????/**
        ????*實(shí)現(xiàn)增強(qiáng)邏輯和對真實(shí)對象方法的調(diào)用
        ????*@param?proxy?生成的動態(tài)代理對象
        ????*@param?method?動態(tài)代理在客戶端執(zhí)行的方法
        ????*@param?args?該方法的參數(shù)列表
        ????*/

        ????@Override
        ????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
        ????????before();
        ????????Object?result?=?method.invoke(target,?args);
        ????????after();
        ????????return?result;
        ????}

        ????private?void?before()?{//方法執(zhí)行前
        ????????System.out.println("方法執(zhí)行前");
        ????}

        ????private?void?after()?{//方法執(zhí)行后
        ????????System.out.println("方法執(zhí)行后");
        ????}
        }
        //第四步
        public?class?Client?{
        ????public?static?void?main(String[]?args)?{
        ????????//保存生成的代理類的字節(jié)碼文class文件:$Proxy0.class
        ????????//下面會細(xì)說$Proxy0.class
        ????????System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles",?"true");
        ????????Subject?target?=?new?RealSubject();
        ????????JDKDynamicProxy?jdkDynamicProxy?=?new?JDKDynamicProxy(target);
        ????????Subject?proxy?=?jdkDynamicProxy.getProxy();
        ????????proxy.request();
        ????}
        }

        運(yùn)行結(jié)果:

        方法執(zhí)行前 訪問具體主題角色方法... 方法執(zhí)行后

        現(xiàn)在有了JDKDynamicProxy,那么我們就再也不需要手動寫代理類了,而是交給JDK去幫我們自動創(chuàng)建。細(xì)心的人你應(yīng)該會發(fā)現(xiàn)JDK的動態(tài)代理通用java代碼和裝飾模式幾乎一毛一樣,但是請記住他們的目的不同,裝飾器設(shè)計(jì)模式是給一個(gè)對象動態(tài)的增加方法(功能),而動態(tài)代理的目的是控制被代理對象的訪問權(quán)。

        JDK動態(tài)代理四大步驟
        1. 定義業(yè)務(wù)接口
        2. 被代理對象實(shí)現(xiàn)業(yè)務(wù)接口
        3. 通過Proxy的靜態(tài)方法newProxyInstance( ClassLoader loader, Class[] interfaces, InvocationHandler h)創(chuàng)建一個(gè)代理對象
        4. 使用代理對象
        JDK動態(tài)代理源碼分析

        JDK動態(tài)代理四個(gè)步驟中最讓人迷惑的就是第三步,第三步到底做了什么?(源碼分析挺乏味的,但是請記住你不讀源碼很多東西永遠(yuǎn)只停留在了解或者皮毛階段,閱讀源碼至少會讓你知道怎么寫出高質(zhì)量的代碼)

        進(jìn)入java.lang.reflect.Proxy類中的

        ?public?static?Object?newProxyInstance(ClassLoader?loader,??Class[]?interfaces,????????????????????????????????????????????InvocationHandler?h)?throws?IllegalArgumentException?{
        ????????//?判斷參數(shù)h是否為空,咱們這里的h=new?JDKDynamicProxy()
        ????????Objects.requireNonNull(h);
        ????????//接口數(shù)組先拷貝一份
        ????????final?Class[]?intfs?=?interfaces.clone();
        ????????//安全檢查
        ????????final?SecurityManager?sm?=?System.getSecurityManager();
        ????????if?(sm?!=?null)?{
        ????????????//檢查創(chuàng)建代理類所需的權(quán)限
        ????????????checkProxyAccess(Reflection.getCallerClass(),?loader,?intfs);
        ????????}
        ????????//最關(guān)鍵的地方
        ????????//查詢(在緩存中已經(jīng)有)或生成指定的代理類的class對象。后面細(xì)說
        ????????Class?cl?=?getProxyClass0(loader,?intfs);
        ????????try?{
        ????????????if?(sm?!=?null)?{
        ????????????????checkNewProxyPermission(Reflection.getCallerClass(),?cl);
        ????????????}
        ????????????//用invocationHandler生成構(gòu)造函數(shù)
        ????????????final?Constructor?cons?=?cl.getConstructor(constructorParams);
        ????????????final?InvocationHandler?ih?=?h;
        ????????????if?(!Modifier.isPublic(cl.getModifiers()))?{
        ????????????????AccessController.doPrivileged(new?PrivilegedAction()?{
        ????????????????????public?Void?run()?{
        ????????????????????????cons.setAccessible(true);
        ????????????????????????return?null;
        ????????????????????}
        ????????????????});
        ????????????}
        ????????????return?cons.newInstance(new?Object[]{h});
        ????????}?catch?(IllegalAccessException|InstantiationException?e)?{
        ????????????throw?new?InternalError(e.toString(),?e);
        ????????}?catch?(InvocationTargetException?e)?{
        ????????????Throwable?t?=?e.getCause();
        ????????????if?(t?instanceof?RuntimeException)?{
        ????????????????throw?(RuntimeException)?t;
        ????????????}?else?{
        ????????????????throw?new?InternalError(t.toString(),?t);
        ????????????}
        ????????}?catch?(NoSuchMethodException?e)?{
        ????????????throw?new?InternalError(e.toString(),?e);
        ????????}
        }
        private?static?Class?getProxyClass0(ClassLoader?loader,?Class...?interfaces)?{
        ????????////?限定代理的接口不能超過65535個(gè)
        ????????if?(interfaces.length?>?65535)?{
        ????????????throw?new?IllegalArgumentException("interface?limit?exceeded");
        ????????}
        ????????////?如果緩存中已經(jīng)存在相應(yīng)接口的代理類,直接返回;否則,使用ProxyClassFactory創(chuàng)建代理類
        ????????return?proxyClassCache.get(loader,?interfaces);
        ????}

        //Proxy的靜態(tài)內(nèi)部類ProxyClassFactory????
        private?static?final?class?ProxyClassFactory
        ????????implements?BiFunction<ClassLoader,?Class[],?Class>
        ????
        {
        ????????//?prefix?for?all?proxy?class?names?代理類前綴
        ????????private?static?final?String?proxyClassNamePrefix?=?"$Proxy";
        ????????//?next?number?to?use?for?generation?of?unique?proxy?class?names
        ????????//生成代理類名稱的計(jì)數(shù)器
        ????????private?static?final?AtomicLong?nextUniqueNumber?=?new?AtomicLong();

        ????????@Override
        ????????public?Class?apply(ClassLoader?loader,?Class[]?interfaces)?{

        ????????????Map,?Boolean>?interfaceSet?=?new?IdentityHashMap<>(interfaces.length);
        ????????????for?(Class?intf?:?interfaces)?{
        ????????????????//校驗(yàn)類加載器是否能通過接口名稱加載該類
        ????????????????Class?interfaceClass?=?null;
        ????????????????try?{
        ????????????????????//根據(jù)接口全限定類名和classLoader,獲取到接口class對象
        ????????????????????interfaceClass?=?Class.forName(intf.getName(),?false,?loader);
        ????????????????}?catch?(ClassNotFoundException?e)?{
        ????????????????}
        ????????????????//如果兩次接口class對象不一致,直接拋出異常,說明創(chuàng)建錯(cuò)誤
        ????????????????if?(interfaceClass?!=?intf)?{
        ????????????????????throw?new?IllegalArgumentException(
        ????????????????????????intf?+?"?is?not?visible?from?class?loader");
        ????????????????}
        ????????????????//校驗(yàn)該類是否是接口類型,這里就是證明為什么JDK動態(tài)代理是代理接口的。
        ????????????????if?(!interfaceClass.isInterface())?{
        ????????????????????throw?new?IllegalArgumentException(
        ????????????????????????interfaceClass.getName()?+?"?is?not?an?interface");
        ????????????????}
        ????????????????//
        ????????????????if?(interfaceSet.put(interfaceClass,?Boolean.TRUE)?!=?null)?{
        ????????????????????throw?new?IllegalArgumentException(
        ????????????????????????"repeated?interface:?"?+?interfaceClass.getName());
        ????????????????}
        ????????????}
        ???????????//代理類包名
        ????????????String?proxyPkg?=?null;?????
        ????????????int?accessFlags?=?Modifier.PUBLIC?|?Modifier.FINAL;
        ????????????//非public接口,代理類的包名與接口的包名相同
        ????????????for?(Class?intf?:?interfaces)?{
        ????????????????int?flags?=?intf.getModifiers();
        ????????????????if?(!Modifier.isPublic(flags))?{
        ????????????????????accessFlags?=?Modifier.FINAL;
        ????????????????????String?name?=?intf.getName();
        ????????????????????int?n?=?name.lastIndexOf('.');
        ????????????????????String?pkg?=?((n?==?-1)???""?:?name.substring(0,?n?+?1));
        ????????????????????if?(proxyPkg?==?null)?{
        ????????????????????????proxyPkg?=?pkg;
        ????????????????????}?else?if?(!pkg.equals(proxyPkg))?{
        ????????????????????????throw?new?IllegalArgumentException(
        ????????????????????????????"non-public?interfaces?from?different?packages");
        ????????????????????}
        ????????????????}
        ????????????}
        ????????????//如果都是public接口設(shè)定全限定類名com.sun.proxy.
        ????????????if?(proxyPkg?==?null)?{
        ????????????????//public代理接口,使用ReflectUtil.PROXY_PACKAGE=com.sun.proxy.包名
        ????????????????proxyPkg?=?ReflectUtil.PROXY_PACKAGE?+?".";
        ????????????}
        ????????????//為代理類生成名字
        ????????????long?num?=?nextUniqueNumber.getAndIncrement();
        ????????????String?proxyName?=?proxyPkg?+?proxyClassNamePrefix?+?num;
        ????????????//真正生成代理類的字節(jié)碼文件的地方:ProxyGenerator類中
        ????????????byte[]?proxyClassFile?=?ProxyGenerator.generateProxyClass(proxyName,?interfaces,?accessFlags);
        ????????????try?{
        ????????????????//使用類加載器將代理類的字節(jié)碼文件加載到JVM中
        ????????????????return?defineClass0(loader,?proxyName,?proxyClassFile,?0,?proxyClassFile.length);
        ????????????}?catch?(ClassFormatError?e)?{
        ????????????????throw?new?IllegalArgumentException(e.toString());
        ????????????}
        ????????}
        ????}????
        ????//ProxyGenerator類中
        ????public?static?byte[]?generateProxyClass(final?String?var0,?Class[]?var1,?int?var2)?{
        ????????ProxyGenerator?var3?=?new?ProxyGenerator(var0,?var1,?var2);
        ????????final?byte[]?var4?=?var3.generateClassFile();
        ????????//是否要將生成代理類的字節(jié)碼文件保存到磁盤中
        ????????if?(saveGeneratedFiles)?{
        ????????????AccessController.doPrivileged(new?PrivilegedAction()?{
        ????????????????public?Void?run()?{
        ????????????????????try?{
        ????????????????????????int?var1?=?var0.lastIndexOf(46);
        ????????????????????????Path?var2;
        ????????????????????????if?(var1?>?0)?{
        ????????????????????????????Path?var3?=?Paths.get(var0.substring(0,?var1).replace('.',?File.separatorChar));
        ????????????????????????????Files.createDirectories(var3);
        ????????????????????????????var2?=?var3.resolve(var0.substring(var1?+?1,?var0.length())?+?".class");
        ????????????????????????}?else?{
        ????????????????????????????var2?=?Paths.get(var0?+?".class");
        ????????????????????????}
        ????????????????????????//如果找不到生成$Proxy0.class可以write方法一直追中下去,將會看到具體的保存路徑
        ????????????????????????//WindowsFileSystemProvider
        ????????????????????????Files.write(var2,?var4,?new?OpenOption[0]);
        ????????????????????????return?null;
        ????????????????????}?catch?(IOException?var4x)?{
        ????????????????????????throw?new?InternalError("I/O?exception?saving?generated?file:?"?+?var4x);
        ????????????????????}
        ????????????????}
        ????????????});
        ????????}
        ????????return?var4;
        ?}
        //具體生成class字節(jié)碼文件的方法
        ?private?byte[]?generateClassFile()?{
        ????????//將object類當(dāng)中的?hashcode,equals,toString方法添加到動態(tài)代理類當(dāng)中
        ????????//addProxyMethod方法后面有分析
        ????????this.addProxyMethod(hashCodeMethod,?Object.class);
        ????????this.addProxyMethod(equalsMethod,?Object.class);
        ????????this.addProxyMethod(toStringMethod,?Object.class);
        ????????Class[]?var1?=?this.interfaces;
        ????????int?var2?=?var1.length;
        ????????int?var3;
        ????????Class?var4;
        ????????//遍歷父接口數(shù)據(jù)
        ????????for(var3?=?0;?var3?????????????var4?=?var1[var3];
        ????????????//獲取每個(gè)接口當(dāng)中的方法
        ????????????Method[]?var5?=?var4.getMethods();
        ????????????int?var6?=?var5.length;
        ?????????????//遍歷接口當(dāng)中的方法,將接口當(dāng)中的方法都添加至動態(tài)代理類當(dāng)中
        ????????????for(int?var7?=?0;?var7?????????????????Method?var8?=?var5[var7];
        ????????????????this.addProxyMethod(var8,?var4);
        ????????????}
        ????????}
        ????????Iterator?var11?=?this.proxyMethods.values().iterator();
        ???????//檢查代理類當(dāng)中的返回類型
        ????????List?var12;
        ????????while(var11.hasNext())?{
        ????????????var12?=?(List)var11.next();
        ????????????checkReturnTypes(var12);
        ????????}
        ????????Iterator?var15;
        ????????try?{
        ?????????????//?將構(gòu)造方法添加至代理類當(dāng)中的方法集合中
        ????????????this.methods.add(this.generateConstructor());
        ????????????var11?=?this.proxyMethods.values().iterator();
        ????????????//遍歷代理類當(dāng)中的方法,此處使用兩層循環(huán),是因?yàn)榉椒ê灻嗤模赡苡卸鄠€(gè)方法
        ????????????while(var11.hasNext())?{
        ????????????????var12?=?(List)var11.next();
        ????????????????var15?=?var12.iterator();
        ????????????????while(var15.hasNext())?{
        ????????????????????ProxyGenerator.ProxyMethod?var16?=?(ProxyGenerator.ProxyMethod)var15.next();
        ????????????????????this.fields.add(new?ProxyGenerator.FieldInfo(var16.methodFieldName,?"Ljava/lang/reflect/Method;",?10));
        ????????????????????this.methods.add(var16.generateMethod());
        ????????????????}
        ????????????}
        ????????????//?將靜態(tài)代碼塊添加進(jìn)去
        ????????????this.methods.add(this.generateStaticInitializer());
        ????????}?catch?(IOException?var10)?{
        ????????????throw?new?InternalError("unexpected?I/O?Exception",?var10);
        ????????}
        ????????//方法個(gè)數(shù)不能超過65535
        ????????if?(this.methods.size()?>?65535)?{
        ????????????throw?new?IllegalArgumentException("method?limit?exceeded");
        ????????}?else?if?(this.fields.size()?>?65535)?{//屬性不能超過65535
        ????????????throw?new?IllegalArgumentException("field?limit?exceeded");
        ????????}?else?{
        ????????????//編寫最終類文件
        ????????????//在開始編寫最終類文件之前,確保為下面的項(xiàng)目保留常量池索引
        ????????????this.cp.getClass(dotToSlash(this.className));
        ????????????this.cp.getClass("java/lang/reflect/Proxy");
        ????????????var1?=?this.interfaces;
        ????????????var2?=?var1.length;

        ????????????for(var3?=?0;?var3?????????????????var4?=?var1[var3];
        ????????????????this.cp.getClass(dotToSlash(var4.getName()));
        ????????????}
        ????????????//設(shè)置只讀,在這之前不允許在常量池中增加信息,因?yàn)橐獙懗A砍乇?/span>
        ????????????this.cp.setReadOnly();

        ????????????ByteArrayOutputStream?var13?=?new?ByteArrayOutputStream();
        ????????????DataOutputStream?var14?=?new?DataOutputStream(var13);

        ????????????try?{
        ????????????????//magic魔法數(shù)字
        ????????????????var14.writeInt(-889275714);
        ????????????????//次版本
        ????????????????var14.writeShort(0);
        ????????????????//主版本
        ????????????????var14.writeShort(49);
        ????????????????this.cp.write(var14);
        ????????????????//訪問表示
        ????????????????var14.writeShort(this.accessFlags);
        ????????????????//本類名稱
        ????????????????var14.writeShort(this.cp.getClass(dotToSlash(this.className)));
        ????????????????var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
        ????????????????//接口
        ????????????????var14.writeShort(this.interfaces.length);
        ????????????????Class[]?var17?=?this.interfaces;
        ????????????????int?var18?=?var17.length;

        ????????????????for(int?var19?=?0;?var19?????????????????????Class?var22?=?var17[var19];
        ????????????????????var14.writeShort(this.cp.getClass(dotToSlash(var22.getName())));
        ????????????????}
        ????????????????//字段
        ????????????????var14.writeShort(this.fields.size());
        ????????????????var15?=?this.fields.iterator();

        ????????????????while(var15.hasNext())?{
        ????????????????????ProxyGenerator.FieldInfo?var20?=?(ProxyGenerator.FieldInfo)var15.next();
        ????????????????????var20.write(var14);
        ????????????????}
        ????????????????//方法
        ????????????????var14.writeShort(this.methods.size());
        ????????????????var15?=?this.methods.iterator();

        ????????????????while(var15.hasNext())?{
        ????????????????????ProxyGenerator.MethodInfo?var21?=?(ProxyGenerator.MethodInfo)var15.next();
        ????????????????????var21.write(var14);
        ????????????????}
        ????????????????//類文件屬性:對于代理類來說沒有類文件屬性
        ????????????????////?(no?ClassFile?attributes?for?proxy?classes)
        ????????????????var14.writeShort(0);
        ????????????????return?var13.toByteArray();
        ????????????}?catch?(IOException?var9)?{
        ????????????????throw?new?InternalError("unexpected?I/O?Exception",?var9);
        ????????????}
        ????????}
        ????}
        ???//給代理類添加方法
        ????private?void?addProxyMethod(Method?var1,?Class?var2)?{
        ????????//方法名
        ????????String?var3?=?var1.getName();
        ????????//方法參數(shù)類型
        ????????Class[]?var4?=?var1.getParameterTypes();
        ????????//返回值類型
        ????????Class?var5?=?var1.getReturnType();
        ????????//異常類型
        ????????Class[]?var6?=?var1.getExceptionTypes();
        ????????//方法簽名
        ????????String?var7?=?var3?+?getParameterDescriptors(var4);
        ????????//根據(jù)方法簽名卻獲得proxyMethods的Value
        ????????Object?var8?=?(List)this.proxyMethods.get(var7);
        ????????//處理多個(gè)代理接口中重復(fù)的方法的情況
        ????????if?(var8?!=?null)?{
        ????????????Iterator?var9?=?((List)var8).iterator();

        ????????????while(var9.hasNext())?{
        ????????????????ProxyGenerator.ProxyMethod?var10?=?(ProxyGenerator.ProxyMethod)var9.next();
        ????????????????if?(var5?==?var10.returnType)?{
        ????????????????????//歸約異常類型以至于讓重寫的方法拋出合適的異常類型,我認(rèn)為這里可能是多個(gè)接口中有相同的方法,
        ????????????????????//而這些相同的方法拋出的異常類型又不同,
        ????????????????????//所以對這些相同方法拋出的異常進(jìn)行了歸約
        ????????????????????ArrayList?var11?=?new?ArrayList();
        ????????????????????collectCompatibleTypes(var6,?var10.exceptionTypes,?var11);
        ????????????????????collectCompatibleTypes(var10.exceptionTypes,?var6,?var11);
        ????????????????????var10.exceptionTypes?=?new?Class[var11.size()];
        ????????????????????//將ArrayList轉(zhuǎn)換為Class對象數(shù)組
        ????????????????????var10.exceptionTypes?=?(Class[])var11.toArray(var10.exceptionTypes);
        ????????????????????return;
        ????????????????}
        ????????????}
        ????????}?else?{
        ????????????var8?=?new?ArrayList(3);
        ????????????this.proxyMethods.put(var7,?var8);
        ????????}
        ????????((List)var8).add(new?ProxyGenerator.ProxyMethod(var3,?var4,?var5,?var6,?var2,?null));
        ????}

        自此源碼分析完畢?,F(xiàn)在回過頭去看自動生成的代理類里到底有什么東東?

        package?com.sun.proxy;

        import?com.tian.swagger.proxy.Subject;
        import?java.lang.reflect.InvocationHandler;
        import?java.lang.reflect.Method;
        import?java.lang.reflect.Proxy;
        import?java.lang.reflect.UndeclaredThrowableException;
        //繼承了Proxy,實(shí)現(xiàn)了Subject
        public?final?class?$Proxy0?extends?Proxy?implements?Subject?{
        ????private?static?Method?m1;
        ????private?static?Method?m2;
        ????private?static?Method?m3;
        ????private?static?Method?m0;
        ????//代理類的構(gòu)造函數(shù),其參數(shù)正是是InvocationHandler實(shí)例,
        ????//Proxy.newInstance方法就是通過通過這個(gè)構(gòu)造函數(shù)來創(chuàng)建代理實(shí)例的
        ????public?$Proxy0(InvocationHandler?var1)?throws??{
        ????????super(var1);
        ????}

        ????public?final?boolean?equals(Object?var1)?throws??{
        ????????try?{
        ????????????return?((Boolean)super.h.invoke(this,?m1,?new?Object[]{var1})).booleanValue();
        ????????}?catch?(RuntimeException?|?Error?var3)?{
        ????????????throw?var3;
        ????????}?catch?(Throwable?var4)?{
        ????????????throw?new?UndeclaredThrowableException(var4);
        ????????}
        ????}

        ????public?final?String?toString()?throws??{
        ????????try?{
        ????????????return?(String)super.h.invoke(this,?m2,?(Object[])null);
        ????????}?catch?(RuntimeException?|?Error?var2)?{
        ????????????throw?var2;
        ????????}?catch?(Throwable?var3)?{
        ????????????throw?new?UndeclaredThrowableException(var3);
        ????????}
        ????}

        ????public?final?int?hashCode()?throws??{
        ????????try?{
        ????????????return?((Integer)super.h.invoke(this,?m0,?(Object[])null)).intValue();
        ????????}?catch?(RuntimeException?|?Error?var2)?{
        ????????????throw?var2;
        ????????}?catch?(Throwable?var3)?{
        ????????????throw?new?UndeclaredThrowableException(var3);
        ????????}
        ????}
        ????//上面三個(gè)方法對應(yīng)的是hashCode、toString、equals

        ????//重寫接口Subject中定義的方法request
        ????public?final?void?request()?throws??{
        ????????try?{
        ????????????//h就是Proxy類中的變量protected?InvocationHandler?h;
        ????????????//this就是當(dāng)前$Proxy0對象;
        ????????????//m3就是Class.forName("com.tian.swagger.proxy.Subject").getMethod("request",?new?Class[0]);
        ????????????//即是通過全路徑名,反射獲取的目標(biāo)對象中的真實(shí)方法加參數(shù)
        ????????????super.h.invoke(this,?m3,?(Object[])null);
        ????????}?catch?(RuntimeException?|?Error?var2)?{
        ????????????throw?var2;
        ????????}?catch?(Throwable?var3)?{
        ????????????throw?new?UndeclaredThrowableException(var3);
        ????????}
        ????}
        ????//?靜態(tài)代碼塊對變量進(jìn)行一些初始化工作
        ????static?{
        ????????try?{
        ????????????//這里每個(gè)方法對象?和類的實(shí)際方法綁定
        ????????????m1?=?Class.forName("java.lang.Object").getMethod("equals",?Class.forName("java.lang.Object"));
        ????????????m2?=?Class.forName("java.lang.Object").getMethod("toString");
        ????????????m3?=?Class.forName("com.tian.swagger.proxy.Subject").getMethod("request");
        ????????????m0?=?Class.forName("java.lang.Object").getMethod("hashCode");
        ????????}?catch?(NoSuchMethodException?var2)?{
        ????????????throw?new?NoSuchMethodError(var2.getMessage());
        ????????}?catch?(ClassNotFoundException?var3)?{
        ????????????throw?new?NoClassDefFoundError(var3.getMessage());
        ????????}
        ????}
        }

        當(dāng)代理對象生成后,最后由InvocationHandler的invoke()方法調(diào)用目標(biāo)方法:在動態(tài)代理中InvocationHandler是核心,每個(gè)代理實(shí)例都具有一個(gè)關(guān)聯(lián)的調(diào)用處理程序(InvocationHandler)。對代理實(shí)例調(diào)用方法時(shí),將對方法調(diào)用進(jìn)行編碼并將其指派到它的調(diào)用處理程序(InvocationHandler)的invoke()方法。所以對代理方法的調(diào)用都是通InvocationHadler的invoke來實(shí)現(xiàn)中,而invoke方法根據(jù)傳入的代理對象,方法和參數(shù)來決定調(diào)用代理的哪個(gè)方法。具體方法簽名如下:

        invoke(Object?Proxy,Method?method,Object[]?args)

        從反編譯源碼分析調(diào)用invoke()過程:從反編譯后的源碼看$Proxy0類繼承了Proxy類,同時(shí)實(shí)現(xiàn)了Subject接口,即代理類接口,所以才能強(qiáng)制將代理對象轉(zhuǎn)換為Subject接口,然后調(diào)用$Proxy0中的request()方法。$Proxy0中request()源碼:

        ????//接口Subject中定義的放任request
        ????public?final?void?request()?throws??{
        ????????try?{
        ?????????????//h就是Proxy類中的變量protected?InvocationHandler?h;
        ????????????//this就是當(dāng)前$Proxy0對象;
        ????????????//m3就是Class.forName("com.tian.swagger.proxy.Subject").getMethod("request",?new?Class[0]);
        ????????????//即是通過全路徑名,反射獲取的目標(biāo)對象中的真實(shí)方法加參數(shù)
        ????????????//后面那個(gè)null是方法參數(shù),因?yàn)镾ubject的方法request參數(shù)為空
        ????????????super.h.invoke(this,?m3,?(Object[])null);
        ????????}?catch?(RuntimeException?|?Error?var2)?{
        ????????????throw?var2;
        ????????}?catch?(Throwable?var3)?{
        ????????????throw?new?UndeclaredThrowableException(var3);
        ????????}
        ????}

        所以成功的調(diào)到了InvocationHandler中的invoke()方法,但是invoke()方法在我們自定義的JDKDynamicProxy中實(shí)現(xiàn),JDKDynamicProxy中的invoke()方法:

        @Override
        public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
        ?????before();
        ?????Object?result?=?method.invoke(target,?args);
        ?????after();
        ?????return?result;
        }

        終于回到咱們寫的代碼里了。不容易吧,簡單JDK動態(tài)代理繞了這么大一圈。

        通過以上分析應(yīng)該收獲:

        1,JDK動態(tài)代理只能代理接口,源碼里有判斷,不是接口就直接拋異常

        //校驗(yàn)該類是否是接口類型,這里就是證明為什么JDK動態(tài)代理是代理接口的。
        ?if?(!interfaceClass.isInterface())?{
        ????throw?new?IllegalArgumentException(?interfaceClass.getName()?+?"?is?not?an?interface");
        ??}

        2,代理類是如何生成的

        3,代理類結(jié)構(gòu)

        4,是如何調(diào)到自己定義的invoke方法的

        JDK動態(tài)代理源碼總結(jié)

        1,生成代理類$Proxy.class字節(jié)碼

        Proxy.newProxyInstance()-->getProxyClass()--->ProxyClassFactory.apply()--->ProxyGenerator.getGenerateProxyClass()

        2,調(diào)用Constructor.newInstance()實(shí)例化

        3,調(diào)用第2步生成的代理對象中的invoke方法,最后調(diào)到JDKDynamicProxy中的invoke方法,最后調(diào)到被代理對象的實(shí)現(xiàn)方法中

        通過以上的分析我們知道了JDK動態(tài)代理的使用和原理,也領(lǐng)略Java動態(tài)代理的強(qiáng)大之處,但是不難看出來使用JDK動態(tài)代理也有著它的局限性,JDK動態(tài)代理是在JVM內(nèi)部動態(tài)的生成class字節(jié)碼對象(代理類.class),但是JDK動態(tài)代理只能針對接口進(jìn)行操作,也就說它只適用于對接口的實(shí)現(xiàn)類去進(jìn)行代理。因?yàn)橛袝r(shí)候咱們希望對普通類進(jìn)行代理,使用JDK動態(tài)代理就無法搞下去,于是另外一個(gè)強(qiáng)大的動態(tài)代理CGlib出現(xiàn)了,CGlib就能解決對普通類進(jìn)行代理的問題。

        CGlib動態(tài)代理

        定義
        Byte?Code?Generation?Library?is?high?level?API?to?generate?and?transform?Java?byte?code.?It?is?used?by?AOP,?testing,?data?access?frameworks?to?generate?dynamic?proxy?objects?and?intercept?field?access.

        CGlib(Code Generation Library)是一個(gè)開源項(xiàng)目;是一個(gè)強(qiáng)大的,高性能,高質(zhì)量的Code生成類庫,它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口,它被AOP、測試、數(shù)據(jù)訪問框架用于生成動態(tài)代理對象和攔截字段訪問。

        CGlib包的底層是通過使用一個(gè)小而快的字節(jié)碼處理框架ASM,來轉(zhuǎn)換字節(jié)碼并生成新的類;CGlib是針對類來實(shí)現(xiàn)代理的,原理是對指定的業(yè)務(wù)類生成一個(gè)子類,并覆蓋其中業(yè)務(wù)方法實(shí)現(xiàn)代理;所以CGlib可以為無接口的類直接做代理,當(dāng)然有接口的類也是可以的并無影響。

        pom

        <dependency>
        ?????<groupId>cglibgroupId>
        ?????<artifactId>cglibartifactId>
        ?????<version>3.2.12version>
        dependency>
        Java代碼
        public?class?TicketConcrete?{
        ????public?void?buy()?{
        ????????System.out.println("買到火車票了");
        ????}
        }
        public?class?CattlePersonMethodInterceptor?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);
        ????????System.out.println("黃牛把火車票給老田");
        ????????return?res;
        ????}
        }
        public?class?Client?{
        ????public?static?void?main(String[]?args)?{
        ????????CattlePersonMethodInterceptor?cattlePerson?=?new?CattlePersonMethodInterceptor();
        ????????Enhancer?enhancer?=?new?Enhancer();
        ????????enhancer.setSuperclass(TicketConcrete.class);
        ????????enhancer.setCallback(cattlePerson);
        ????????TicketConcrete?person?=?(TicketConcrete)?enhancer.create();
        ????????person.buy();
        ????}
        }

        運(yùn)行結(jié)果:

        黃牛去買火車票 買到火車票了 黃牛把火車票給老田

        上面已經(jīng)提到,CGlib庫是基于ASM的上層應(yīng)用。對于代理沒有實(shí)現(xiàn)接口的類,CGlib非常實(shí)用。本質(zhì)上來說,對于需要被代理的類,它只是動態(tài)生成一個(gè)子類以覆蓋非final的方法,同時(shí)綁定鉤子回調(diào)自定義的攔截器。值得說的是,它比JDK動態(tài)代理還要快。

        CGlib 部分源碼分析

        cglib.jar包目錄:

        本文只關(guān)心proxy目錄(CGlib動態(tài)代理相關(guān)主要類目錄).

        net.sf.cglib.
        ??????????? core:底層字節(jié)碼操作類;大部分與ASP相關(guān)。
        ??????????? transform:編譯期、運(yùn)行期的class文件轉(zhuǎn)換類。
        ??????????? proxy:代理創(chuàng)建類、方法攔截類。
        ??????????? reflect:更快的反射類、C#風(fēng)格的代理類。
        ??????????? util:集合排序工具類
        ??????????? beans:JavaBean相關(guān)的工具類

        源碼從enhancer.create()開始看,因?yàn)檫@里返回的Object直接強(qiáng)轉(zhuǎn)為TicketConcrete(被代理的類)

        Enhancer類中

        //這里沒有具體什么
        public?Object?create()?{
        ???????classOnly?=?false;
        ???????argumentTypes?=?null;
        ???????return?createHelper();
        }
        //構(gòu)建幫助器
        private?Object?createHelper()?{
        ???//提前驗(yàn)證回調(diào)類型和filter
        ???preValidate();
        ????//生成key
        ???Object?key?=?KEY_FACTORY.newInstance((superclass?!=?null)???superclass.getName()?:?null,
        ??????????ReflectUtils.getNames(interfaces),
        ??????????filter?==?ALL_ZERO???null?:?new?WeakCacheKey(filter),
        ??????????callbackTypes,
        ??????????useFactory,
        ??????????interceptDuringConstruction,
        ??????????serialVersionUID);
        ????//復(fù)制個(gè)當(dāng)前key
        ????this.currentKey?=?key;
        ????//使用key構(gòu)建代理對象,個(gè)人認(rèn)為這里代碼其實(shí)可以直接寫成?return?super.create(key);
        ????//看得出來這里的create方法很關(guān)鍵,AbstractClassGenerator.create()
        ????Object?result?=?super.create(key);
        ????return?result;
        }

        AbstractClassGenerator類中

        private?static?volatile?Map?CACHE?=?new?WeakHashMap();
        protected?Object?create(Object?key)?{
        ????????try?{
        ????????????//獲取類加載器AppClassLoader
        ????????????ClassLoader?loader?=?getClassLoader();
        ????????????//這里和jdk動態(tài)代理類似,也用到了緩存,classloader為key
        ????????????Map?cache?=?CACHE;
        ????????????ClassLoaderData?data?=?cache.get(loader);
        ????????????//data==null
        ????????????if?(data?==?null)?{
        ????????????????synchronized?(AbstractClassGenerator.class)?{
        ????????????????????cache?=?CACHE;
        ????????????????????data?=?cache.get(loader);
        ????????????????????//data==null
        ????????????????????if?(data?==?null)?{
        ????????????????????????//沒有數(shù)據(jù)則構(gòu)建新緩存
        ????????????????????????Map?newCache?=?new?????????????????????????
        ?????????????????????????????WeakHashMap(cache);
        ????????????????????????//關(guān)鍵點(diǎn):這里生成了class并存入緩存
        ????????????????????????data?=?new?ClassLoaderData(loader);
        ????????????????????????newCache.put(loader,?data);
        ????????????????????????CACHE?=?newCache;
        ????????????????????}
        ????????????????}
        ????????????}
        ????????????this.key?=?key;
        ????????????//從緩存中取數(shù)據(jù)
        ????????????Object?obj?=?data.get(this,?getUseCache());
        ????????????//根據(jù)返回類型不同,然后進(jìn)行對應(yīng)的實(shí)例化
        ????????????if?(obj?instanceof?Class)?{
        ????????????????return?firstInstance((Class)?obj);
        ????????????}
        ????????????return?nextInstance(obj);
        ????????}?catch?(RuntimeException?e|Error?e|Exception?e)?{
        ????????????throw?new?CodeGenerationException(e);
        ????????}
        ????}
        ??public?ClassLoaderData(ClassLoader?classLoader)?{
        ???????????//類加載器是否存在
        ????????????if?(classLoader?==?null)?{
        ????????????????throw?new?IllegalArgumentException("classLoader?==?null?is?not?yet?supported");
        ????????????}
        ????????????//?弱引用也是用來描述非必需對象的,當(dāng)JVM進(jìn)行垃圾回收時(shí),
        ????????????//WeakReference無論內(nèi)存是否充足,都會回收被弱引用關(guān)聯(lián)的對象
        ????????????this.classLoader?=?new?WeakReference(classLoader);
        ????????????Function?load?=
        ????????????????????new?Function()?{
        ????????????????????????public?Object?apply(AbstractClassGenerator?gen)?{
        ????????????????????????????//生成Class對象
        ????????????????????????????Class?klass?=?gen.generate(ClassLoaderData.this);
        ????????????????????????????return?gen.wrapCachedClass(klass);
        ????????????????????????}
        ????????????????????};
        ????????????generatedClasses?=?new?LoadingCache(GET_KEY,?
        ????????????????????????????????????????????????????????????????????????????????????????load);
        ????????}
        //生成Class對象
        protected?Class?generate(ClassLoaderData?data)?{
        ????????Class?gen;
        ????????Object?save?=?CURRENT.get();
        ????????CURRENT.set(this);
        ????????try?{
        ????????????ClassLoader?classLoader?=?data.getClassLoader();
        ????????????if?(classLoader?==?null)?{
        ?????????????throw?new?IllegalStateException("ClassLoader?is?null?while?trying?to?define?class?"?+?getClassName()?+?".?It?seems?that?the?loader?has?been?expired?from?a?weak?reference?somehow.?"?+??"Please?file?an?issue?at?cglib's?issue?tracker.");
        ????????????}
        ????????????synchronized?(classLoader)?{
        ??????????????//生成代理類的名字
        ??????????????//com.tian.swagger.proxy.cglib.TicketConcrete$$FastClassByCGLIB$$56a92ac1
        ??????????????//三部分組成:被代理對象的類全名+FastClassBYCGLIB+hashcode
        ??????????????String?name?=?generateClassName(data.getUniqueNamePredicate());??????????????
        ??????????????data.reserveName(name);
        ??????????????this.setClassName(name);
        ????????????}
        ????????????if?(attemptLoad)?{
        ????????????????try?{
        ????????????????????gen?=?classLoader.loadClass(getClassName());
        ????????????????????return?gen;
        ????????????????}?catch?(ClassNotFoundException?e)?{
        ????????????????????//?ignore
        ????????????????}
        ????????????}
        ????????????//根據(jù)策略生成不同的字節(jié)碼
        ????????????byte[]?b?=?strategy.generate(this);
        ????????????String?className?=?ClassNameReader.getClassName(new?ClassReader(b));
        ????????????ProtectionDomain?protectionDomain?=?getProtectionDomain();
        ????????????//利用反射生成class對象
        ????????????synchronized?(classLoader)?{?//?just?in?case
        ????????????????if?(protectionDomain?==?null)?{
        ????????????????????gen?=?ReflectUtils.defineClass(className,?b,?classLoader);
        ????????????????}?else?{
        ????????????????????gen?=?ReflectUtils.defineClass(className,?b,?classLoader,?protectionDomain);
        ????????????????}
        ????????????}
        ????????????return?gen;
        ????????}?catch?(RuntimeException?e|Error?e)?{
        ????????????throw?e;
        ????????}?catch?(Exception?e)?{
        ????????????throw?new?CodeGenerationException(e);
        ????????}?finally?{
        ????????????CURRENT.set(save);
        ????????}
        ????}
        //生成字節(jié)碼
        public?byte[]?generate(ClassGenerator?cg)?throws?Exception?{
        ????????DebuggingClassWriter?cw?=?getClassVisitor();
        ????????transform(cg).generateClass(cw);
        ????????return?transform(cw.toByteArray());
        }
        protected?ClassGenerator?transform(ClassGenerator?cg)?throws?Exception?{
        ????return?cg;
        }
        public?interface?ClassGenerator?{
        ????void?generateClass(ClassVisitor?v)?throws?Exception;
        }

        ClassGenerator實(shí)現(xiàn)類AbstractClassGenerator,AbstractClassGenerator的子類主要有

        Enhancer
        FastClass.Generator
        KeyFactory.Generator

        把生成的class文件保存,會生成以上三個(gè)class文件

        public?class?Client?{
        ????public?static?void?main(String[]?args)?{
        ????????//把生成的class文件保存,會生成以上三個(gè)class文件
        ????????System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,?"D:\\");
        ????????long?s=System.currentTimeMillis();
        ????????CattlePersonMethodInterceptor?cattlePerson?=?new?CattlePersonMethodInterceptor();
        ????????Enhancer?enhancer?=?new?Enhancer();
        ????????enhancer.setSuperclass(TicketConcrete.class);
        ????????enhancer.setCallback(cattlePerson);
        ????????TicketConcrete?person?=?(TicketConcrete)?enhancer.create();
        ????????person.buy();
        ????????System.out.println(System.currentTimeMillis()-s);
        ????}
        }

        最終生成相關(guān)的三個(gè)Class

        com.tian.swagger.proxy.cglib.TicketConcrete$$EnhancerByCGLIB$$e39d634f
        com.tian.swagger.proxy.cglib.TicketConcrete$$FastClassByCGLIB$$56a92ac1
        com.tian.swagger.proxy.cglib.TicketConcrete$$EnhancerByCGLIB$$e39d634f$$FastClassByCGLIB$$ba31b84d

        重點(diǎn)關(guān)注TicketConcrete$$EnhancerByCGLIB$$e39d634f文件中主要內(nèi)容:

        package?com.tian.swagger.proxy.cglib;

        import?java.lang.reflect.Method;
        import?net.sf.cglib.core.ReflectUtils;
        import?net.sf.cglib.core.Signature;
        import?net.sf.cglib.proxy.Callback;
        import?net.sf.cglib.proxy.Factory;
        import?net.sf.cglib.proxy.MethodInterceptor;
        import?net.sf.cglib.proxy.MethodProxy;
        //繼承了TicketConcrete,證明了CGlib是針對被代理類進(jìn)行生成一個(gè)子類來實(shí)現(xiàn)代理的
        //和jdk動態(tài)代理不一樣,動態(tài)代理是集成Proxy類實(shí)現(xiàn)了我們的接口,
        //而cglib是集成了我們的類重寫了父類中的方法
        public?class?TicketConcrete$$EnhancerByCGLIB$$e39d634f?
        ???????extends?TicketConcrete
        ???????implements?Factory?
        {
        ????private?boolean?CGLIB$BOUND;
        ????public?static?Object?CGLIB$FACTORY_DATA;
        ????private?static?final?ThreadLocal?CGLIB$THREAD_CALLBACKS;
        ????private?static?final?Callback[]?CGLIB$STATIC_CALLBACKS;
        ????private?MethodInterceptor?CGLIB$CALLBACK_0;
        ????private?static?Object?CGLIB$CALLBACK_FILTER;
        ????private?static?final?Method?CGLIB$buy$0$Method;
        ????private?static?final?MethodProxy?CGLIB$buy$0$Proxy;
        ????private?static?final?Object[]?CGLIB$emptyArgs;
        ????private?static?final?Method?CGLIB$equals$1$Method;
        ????private?static?final?MethodProxy?CGLIB$equals$1$Proxy;
        ????private?static?final?Method?CGLIB$toString$2$Method;
        ????private?static?final?MethodProxy?CGLIB$toString$2$Proxy;
        ????private?static?final?Method?CGLIB$hashCode$3$Method;
        ????private?static?final?MethodProxy?CGLIB$hashCode$3$Proxy;
        ????private?static?final?Method?CGLIB$clone$4$Method;
        ????private?static?final?MethodProxy?CGLIB$clone$4$Proxy;

        ????static?void?CGLIB$STATICHOOK1()?{
        ????????CGLIB$THREAD_CALLBACKS?=?new?ThreadLocal();
        ????????CGLIB$emptyArgs?=?new?Object[0];
        ????????//var0為代理對象com.tian.swagger.proxy.cglib.TicketConcrete
        ????????Class?var0?=?Class.forName("com.tian.swagger.proxy.cglib.TicketConcrete$$EnhancerByCGLIB$$e39d634f");
        ????????Class?var1;
        ????????Method[]?var10000?=?ReflectUtils.findMethods(new?String[]{"equals",?"(Ljava/lang/Object;)Z",?"toString",?"()Ljava/lang/String;",?"hashCode",?"()I",?"clone",?"()Ljava/lang/Object;"},?(var1?=?Class.forName("java.lang.Object")).getDeclaredMethods());
        ????????CGLIB$equals$1$Method?=?var10000[0];
        ????????CGLIB$equals$1$Proxy?=?MethodProxy.create(var1,?var0,?"(Ljava/lang/Object;)Z",?"equals",?"CGLIB$equals$1");
        ????????CGLIB$toString$2$Method?=?var10000[1];
        ????????CGLIB$toString$2$Proxy?=?MethodProxy.create(var1,?var0,?"()Ljava/lang/String;",?"toString",?"CGLIB$toString$2");
        ????????CGLIB$hashCode$3$Method?=?var10000[2];
        ????????CGLIB$hashCode$3$Proxy?=?MethodProxy.create(var1,?var0,?"()I",?"hashCode",?"CGLIB$hashCode$3");
        ????????CGLIB$clone$4$Method?=?var10000[3];
        ????????CGLIB$clone$4$Proxy?=?MethodProxy.create(var1,?var0,?"()Ljava/lang/Object;",?"clone",?"CGLIB$clone$4");
        ????????//被代理的方法被代理方法buy()
        ????????CGLIB$buy$0$Method?=?ReflectUtils.findMethods(new?String[]{"buy",?"()V"},?(var1?=?Class.forName("com.tian.swagger.proxy.cglib.TicketConcrete")).getDeclaredMethods())[0];
        ????????//代理方法
        ????????CGLIB$buy$0$Proxy?=?MethodProxy.create(var1,?var0,?"()V",?"buy",?"CGLIB$buy$0");
        ????}
        ????//這個(gè)方法在fastClass中調(diào)用,此調(diào)用是執(zhí)行真正的邏輯
        ????final?void?CGLIB$buy$0()?{
        ????????super.buy();
        ????}
        ????//方法重寫
        ????public?final?void?buy()?{
        ????????//判斷目標(biāo)類是否有設(shè)置回調(diào):enhancer.setCallback(this);
        ????????MethodInterceptor?var10000?=?this.CGLIB$CALLBACK_0;
        ????????if?(this.CGLIB$CALLBACK_0?==?null)?{
        ????????????CGLIB$BIND_CALLBACKS(this);
        ????????????var10000?=?this.CGLIB$CALLBACK_0;
        ????????}
        ????????//設(shè)置了方法的回調(diào)則調(diào)用攔截器方法intercept
        ????????if?(var10000?!=?null)?{
        ????????????var10000.intercept(this,?CGLIB$buy$0$Method,?CGLIB$emptyArgs,?CGLIB$buy$0$Proxy);
        ????????}?else?{
        ????????????super.buy();
        ????????}
        ????}
        ????public?static?MethodProxy?CGLIB$findMethodProxy(Signature?var0)?{
        ????????//省略相關(guān)的代碼
        ????}
        ????//省略調(diào)equals?hashCode?clone等方法??
        }
        CGlib總結(jié)
        • 首先生成代理對象?!緞?chuàng)建增強(qiáng)類enhancer,設(shè)置代理類的父類,設(shè)置回調(diào)攔截方法,返回創(chuàng)建的代理對象】
        • 調(diào)用代理類中的方法?!具@里調(diào)用的代理類中的方法實(shí)際上是重寫的父類的攔截。重寫的方法中會去調(diào)用intercept方法】
        • 調(diào)用intercept,方法中會對調(diào)用代理方法中的invokeSuper方法。而在invokeSuper中維護(hù)了一個(gè)FastClassInfo類,其包含四個(gè)屬性字段,分別為FastClass f1(目標(biāo)類);FastClass f2 (代理類); int i1(目標(biāo)類要執(zhí)行方法的下標(biāo)); int i2(代理類要執(zhí)行方法的下標(biāo)); invokeSuper中會調(diào)用的為代理類中的對應(yīng)方法(代理類繼承父類的時(shí)候,對于其父類的方法,自己會生成兩個(gè)方法,一個(gè)是重寫的方法,一個(gè)是代理生成的方法,這里調(diào)用的即是代理生成的方法)
        • 調(diào)用代理類中的代理方法,代理方法中通過super.method來真正地調(diào)用要執(zhí)行被代理類的方法。

        JDK VS CGlib

        JDK動態(tài)代理只能夠?qū)涌谶M(jìn)行代理,不能對普通的類進(jìn)行代理(因?yàn)樗猩傻拇眍惖母割悶镻roxy,Java類繼承機(jī)制不允許多重繼承);CGLIB能夠代理普通類;JDK動態(tài)代理使用Java原生的反射API進(jìn)行操作,在生成類上比較高效;CGLIB使用ASM框架直接對字節(jié)碼進(jìn)行操作,在類的執(zhí)行過程中比較高效。

        動態(tài)代理典型場景的應(yīng)用

        Mybatis中的使用場景

        Mybatis應(yīng)該算持久化框架中使用率最多之一,細(xì)心的小伙伴有沒有發(fā)現(xiàn),比如我們在使用UserInfoMapper.java是接口,接口不是能實(shí)例化的,那為什么我們還能注入呢?

        ????@Resource
        ????private?UserInfoMapper?userInfoMapper;

        為什么還能userMapper.insert()這么使用呢?先看看Mybatis沒有集成Spring是如何實(shí)例化的。

        <bean?id="userMapper"?class="org.mybatis.spring.mapper.MapperFactoryBean">
        ??<property?name="mapperInterface"?value="org.mybatis.spring.sample.mapper.UserMapper"?/>
        ??<property?name="sqlSessionFactory"?ref="sqlSessionFactory"?/>
        bean>

        上面的MapperFactoryBean就可以實(shí)例化出mapperInterface類型的Bean,因?yàn)镸apperFactoryBean實(shí)現(xiàn)了FactoryBean接口的getObject方法,可以實(shí)例化出我們想要的Bean,實(shí)際上是通過Jdk動態(tài)代理得到的Bean。

        public?T?getObject()?throws?Exception?{
        ????return?getSqlSession().getMapper(this.mapperInterface);
        }

        調(diào)用方式:

        SqlSession?session?=?sqlSessionFactory.openSession();??
        try?{??
        ??User?user=?(User)?session.selectOne("org.mybatis.example.UserMapper.selectBlog",?1);??
        }?finally?{??
        ??session.close();??
        }??

        上面的UserMapper接口是一個(gè)個(gè)的配置來實(shí)例化的,每次需要openSession,close Session,重復(fù)工作太多,這樣肯定比較麻煩,下面看看項(xiàng)目中常用的Mybatis與Spring集成的配置方式。

        "sqlSessionFactory"?class="org.mybatis.spring.SqlSessionFactoryBean">
        ?"mapperLocations"?value="classpath*:com/**/mapper/**/*Mapper*.xml"?/>
        ?????"dataSource"?ref="dataSource"?/>

        這個(gè)SqlSessionFactoryBean會做哪些事呢,主要是把Mapper.xml文件與Mapper.java加載進(jìn)來,根據(jù)namespace加載對應(yīng)的接口類到MapperRegistry,把方法名與Mapper.xml里的Select id對應(yīng)起來等等。MapperRegistry相當(dāng)于是一個(gè)緩存,后面創(chuàng)建代理對象是會用到。

        <bean?class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        ?<property?name="annotationClass"?value="javax.annotation.Autowire">property>?
        ?????<property?name="basePackage"?value="com.***.mapper"?/>
        ?????<property?name="sqlSessionFactoryBeanName"?value="sqlSessionFactory"/>
        bean>

        這里的值設(shè)置,只要是注解就行,不一定是Autowird,它代表只對有注解的接口類創(chuàng)建代理對象,否則,對basePackage下所有接口創(chuàng)建代理對象。

        MapperScannerConfigurer可以對basePackage下所有Mapper接口創(chuàng)建代理對象,而不是像上面一個(gè)個(gè)配置。因?yàn)樗麑?shí)現(xiàn)了接口BeanDefinitionRegistryPostProcessor,它就是用來自定義Bean的,看看源碼它是如何實(shí)現(xiàn)的。

        上面設(shè)置mapperInterface,BeanClass其實(shí)就是上面講的Mybatis沒有集成Spring的配置方式。

        我們知道了代理對象是通過MapperFactoryBean創(chuàng)建的。具體看看是如何創(chuàng)建的。

        根據(jù)接口類創(chuàng)建代理對象:

        /**
        ???*?{@inheritDoc}
        ???*/

        ??public?T?getObject()?throws?Exception?{
        ????return?getSqlSession().getMapper(this.mapperInterface);
        ??}

        這里就用到了之前說的MapperRegistry,只是用來校驗(yàn)該接口是否存在。這里又用到了MapperProxy,是一個(gè)代理類,實(shí)現(xiàn)了InvocationHandler接口。

        ?public?static??T?newMapperProxy(Class?mapperInterface,?SqlSession?sqlSession)?{
        ????ClassLoader?classLoader?=?mapperInterface.getClassLoader();
        ????Class[]?interfaces?=?new?Class[]{mapperInterface};
        ????MapperProxy?proxy?=?new?MapperProxy(sqlSession);
        ????return?(T)?Proxy.newProxyInstance(classLoader,?interfaces,?proxy);
        ??}
        public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{
        ????if?(method.getDeclaringClass()?==?Object.class)?{
        ??????return?method.invoke(this,?args);
        ????}
        ????final?Class?declaringInterface?=?findDeclaringInterface(proxy,?method);
        ????final?MapperMethod?mapperMethod?=?new?MapperMethod(declaringInterface,?method,?sqlSession);
        ????final?Object?result?=?mapperMethod.execute(args);
        ????if?(result?==?null?&&?method.getReturnType().isPrimitive()?&&?!method.getReturnType().equals(Void.TYPE))?{
        ??????throw?new?BindingException("Mapper?method?'"?+?method.getName()?+?"'?("?+?method.getDeclaringClass()?+?")?attempted?to?return?null?from?a?method?with?a?primitive?return?type?("?+?method.getReturnType()?+?").");
        ????}
        ????return?result;
        ??}

        當(dāng)我們調(diào)用Mpper接口方法時(shí),會被MapperProxy代理類攔截調(diào)用,主要調(diào)用實(shí)現(xiàn)就是mapperMethod.execute(args),看看底層實(shí)現(xiàn)。

        public?Object?execute(Object[]?args)?{
        ????Object?result?=?null;
        ????if?(SqlCommandType.INSERT?==?type)?{
        ??????Object?param?=?getParam(args);
        ??????result?=?sqlSession.insert(commandName,?param);
        ????}?else?if?(SqlCommandType.UPDATE?==?type)?{
        ??????Object?param?=?getParam(args);
        ??????result?=?sqlSession.update(commandName,?param);
        ????}?else?if?(SqlCommandType.DELETE?==?type)?{
        ??????Object?param?=?getParam(args);
        ??????result?=?sqlSession.delete(commandName,?param);
        ????}?else?if?(SqlCommandType.SELECT?==?type)?{
        ??????if?(returnsVoid?&&?resultHandlerIndex?!=?null)?{
        ????????executeWithResultHandler(args);
        ??????}?else?if?(returnsMany)?{
        ????????result?=?executeForMany(args);
        ??????}?else?if?(returnsMap)?{
        ????????result?=?executeForMap(args);
        ??????}?else?{
        ????????Object?param?=?getParam(args);
        ????????result?=?sqlSession.selectOne(commandName,?param);?//跟上面沒有集成Spring調(diào)用方式一樣的。
        ??????}
        ????}?else?{
        ??????throw?new?BindingException("Unknown?execution?method?for:?"?+?commandName);
        ????}
        ????return?result;
        ??}

        以上就是代理模式、動態(tài)代理(JDK、CGLib)、MyBatis中的動態(tài)代理的使用。

        好了,就這么多了。



        推薦閱讀:

        MySQL一共可以創(chuàng)建多少張表

        出乎意料,刷新認(rèn)知:讀者朋友們藏龍臥虎



        歡迎關(guān)注微信公眾號:互聯(lián)網(wǎng)全棧架構(gòu),收取更多有價(jià)值的信息。


        瀏覽 46
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            美女扒开尿道让男人桶 | 中文字幕自拍偷拍 | 啊~用力cao我cao死我视频 | 日韩v欧美v日本v亚洲v国产v | 久久久久成人网站 | 无尽~捆绑~强制~露出~3d | 国产熟妇自偷自产二区 | 五月天之婷婷 | 国产秘 精品区二区三区日本 | 老公亲秘密花园的时候该如何回应 |