<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          傀儡政權(quán)之代理模式

          共 4798字,需瀏覽 10分鐘

           ·

          2020-12-07 16:10

          點(diǎn)擊上方「藍(lán)字」關(guān)注我們

          代理模式應(yīng)用非常廣泛,特別java領(lǐng)域的Spring框架,可以說把代理模式運(yùn)用到極致。其中Spring的代理又分JDK動態(tài)代理和cglib動態(tài)代理。這類不打算深入講解Spring的動態(tài)代理,而是深入講解一下GOF 23的代理模式。


          0x01:代理模式

          代理模式:給某一個(gè)對象提供一個(gè)代理對象,并由代理對象控制對原對象的引用。通俗的來講代理模式就是生活中常見的中介。好比房地產(chǎn)中介,買賣房子時(shí)通過中介,既安全,又方便,唯一的不足就是需要交納一筆不菲的傭金。代理模式的通用UML類圖如下

          • 抽象角色(Subject):通過接口或抽象類聲明真實(shí)角色實(shí)現(xiàn)的業(yè)務(wù)方法。

          • 真實(shí)角色(RealSubject):實(shí)現(xiàn)抽象角色,定義真實(shí)角色所要實(shí)現(xiàn)的業(yè)務(wù)邏輯,供代理角色調(diào)用。

          • 代理角色(Proxy):實(shí)現(xiàn)抽象角色,是真實(shí)角色的代理,通過真實(shí)角色的業(yè)務(wù)邏輯方法來實(shí)現(xiàn)抽象方法,并可以附加額外的操作來增強(qiáng)功能和業(yè)務(wù)能力。

          抽象角色(Subject):

          public?interface?Subject?{

          ????public?void?request();

          ?}

          真實(shí)角色(RealSubject)

          public?class?RealSubject?implements?Subject?{

          ????@Override
          ????public?void?request()?{
          ????????System.out.println("真實(shí)的請求RealSubject");
          ????}

          }

          代理角色(Proxy)

          public?class?Proxy?implements?Subject?{

          ????private?RealSubject?realSubject?=?null;

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

          ????@Override
          ????public?void?request()?{
          ????????this.doBefore();
          ????????this.realSubject.request();
          ????????this.doAfter();
          ????}

          ????//前置處理
          ????private?void?doBefore()?{
          ????????System.out.println("-------do?before------");
          ????}

          ????//后綴處理
          ????private?void?doAfter()?{
          ????????System.out.println("-------do?after-------");
          ????}
          }

          Client客戶端:

          public?class?Client?{

          ????public?static?void?main(String[]?args)?{
          ????????Proxy?proxy?=?new?Proxy();
          ????????proxy.request();
          ????}

          }

          通過以上的代碼就實(shí)現(xiàn)了一個(gè)簡單的代理模式,這種實(shí)現(xiàn)方式也叫靜態(tài)代理;但是實(shí)在項(xiàng)目、框架中的代理模式可并沒有這么簡單,比這復(fù)雜多了。

          靜態(tài)代理的特點(diǎn):

          • 靜態(tài)代理由開發(fā)者去生成固定的代碼進(jìn)行編譯。需要定義接口或抽象的父類作為抽象目標(biāo)類,具體目標(biāo)類和代理類一起實(shí)現(xiàn)相同的接口或繼承相同的類,然后通過調(diào)用相同的方法來調(diào)用目標(biāo)對象的方法。

          • 靜態(tài)代理需要目標(biāo)對象和代理對象實(shí)現(xiàn)相同的接口。可以在不修改目標(biāo)對象功能的前提下,對目標(biāo)功能進(jìn)行擴(kuò)展和增強(qiáng)。

          • 雖然靜態(tài)代理可以很好的對目標(biāo)對象進(jìn)行功能擴(kuò)展,但是每一個(gè)真實(shí)角色都需要建立代理類,工作量較大且不易管理;而且如果接口發(fā)生改變的話,代理類也必須進(jìn)行相應(yīng)的修改,這時(shí)動態(tài)代理的作用就顯現(xiàn)出來了。


          0x02:動態(tài)代理

          動態(tài)代理與靜態(tài)代理的區(qū)別在于:動態(tài)代理類的字節(jié)碼是在程序運(yùn)行時(shí)由Java反射機(jī)制動態(tài)生成,無需程序員手工編寫它的源代碼動態(tài)代理分為JDK動態(tài)代理和cglib動態(tài)代理。

          • JDK動態(tài)代理是jre提供的類庫,只需依賴JDK,就可以直接使用,無需依賴第三方類庫。

          最近蛋殼真是火的一塌糊涂,先來個(gè)抽象房東接口

          public?interface?IFangDong?{

          ????public?void?hire(String?area);

          }

          房東實(shí)現(xiàn)接口

          public?class?FangDong?implements?IFangDong{

          ????@Override
          ????public?void?hire(String?area)?{
          ????????System.out.println(area);
          ????}

          }

          房東一般指那些手握幾套甚至幾十臺房子的人,房東有房子出租,但是房子太多管不過來,一般不會自己聯(lián)系要租房子的人;而是交個(gè)房地產(chǎn)中介。創(chuàng)建一個(gè)類,便于理解該類的類名以Prox結(jié)尾,但是該類不是代理類,因?yàn)樗]有實(shí)現(xiàn)IFangDong接口,無法對外提供服務(wù),僅僅是一個(gè)wrapper類(包裝類)。

          import?java.lang.reflect.InvocationHandler;
          import?java.lang.reflect.Method;
          import?java.lang.reflect.Proxy;

          public?class?FangDongProxy?implements?InvocationHandler{

          ????//?目標(biāo)類,也就是被代理對象
          ????private?Object?target;

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

          ????@Override
          ????public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable
          ????
          {
          ????????//?這里可以做增強(qiáng)
          ????????System.out.println("必須租給程序員~~因?yàn)樗麄內(nèi)松靛X多");
          ????????Object?result?=?method.invoke(target,?args);
          ????????return?result;
          ????}

          ????//?生成代理類
          ????public?Object?creatProxyedObj()
          ????
          {
          ????????return?Proxy.newProxyInstance(target.getClass().getClassLoader(),?target.getClass().getInterfaces(),?this);
          ????}?
          }

          方法creatProxyedObj返回的對象才是代理類,它需要三個(gè)參數(shù),前兩個(gè)參數(shù)的意思是在同一個(gè)classloader下通過接口創(chuàng)建出一個(gè)對象,該對象需要一個(gè)屬性,也就是第三個(gè)參數(shù),它是一個(gè)InvocationHandler對象。上述代理的代碼使用過程一般如下:

          • new一個(gè)目標(biāo)對象

          • new一個(gè)InvocationHandler,將目標(biāo)對象set進(jìn)去

          • 通過creatProxyedObj創(chuàng)建代理對象,強(qiáng)轉(zhuǎn)為目標(biāo)對象的接口類型即可使用,實(shí)際上生成的代理對象實(shí)現(xiàn)了目標(biāo)接口。

          public?class?Client?{

          ????public?static?void?main(String[]?args)?{
          ????????IFangDong?fd?=?new?FangDong();
          ????????FangDongProxy?proxy?=?new?FangDongProxy();
          ????????proxy.setTarget(fd);?
          ????????Object?obj?=?proxy.creatProxyedObj();
          ????????IFangDong?fangDong?=?(IFangDong)obj;
          ????????fangDong.hire("我有130平大房子出租~~");
          ????}
          }

          從以上代碼可以看出如果使用JDK動態(tài)代理,必須實(shí)現(xiàn)InvocationHandler類,然后再該類的invoke方法做增強(qiáng)和調(diào)用目標(biāo)類的相應(yīng)方法。

          • cglib動態(tài)代理,需要引入第三方類庫cglib-x.x.x.jar

          通過繼承可以繼承父類所有的公開方法,然后重寫這些方法;在重寫時(shí)對方法進(jìn)行增強(qiáng),這就是cglib的核心思想。根據(jù)里氏代換原則(LSP),父類出現(xiàn)的地方,子類都可以出現(xiàn),所以cglib實(shí)現(xiàn)的代理就一定可以被正常使用。

          引入jar包

          <dependency>
          ????<groupId>cglibgroupId>

          ????<artifactId>cglibartifactId>
          ????<version>3.1version>
          dependency>
          實(shí)現(xiàn)cglib動態(tài)代理
          import?java.lang.reflect.Method;

          import?net.sf.cglib.proxy.Enhancer;
          import?net.sf.cglib.proxy.MethodInterceptor;
          import?net.sf.cglib.proxy.MethodProxy;

          public?class?FangDongCglibProxy?implements?MethodInterceptor?{

          ????//?根據(jù)一個(gè)類型產(chǎn)生代理類,此方法不要求一定放在MethodInterceptor中
          ????public?Object?CreatProxyedObj(Class?clazz)?{
          ????????Enhancer?enhancer?=?new?Enhancer();
          ????????enhancer.setSuperclass(clazz);
          ????????enhancer.setCallback(this);
          ????????return?enhancer.create();
          ????}

          ????@Override
          ????public?Object?intercept(Object?obj,?Method?method,?Object[]?args,?MethodProxy?methodProxy)?throws?Throwable?{
          ????????//?這里增強(qiáng)
          ????????System.out.println("FangDongCglibProxy》》》必須租給程序員~~因?yàn)樗麄內(nèi)松靛X多");
          ????????return?methodProxy.invokeSuper(obj,?args);
          ????}

          }
          從上面代碼可以看出,cglib和jdk動態(tài)代理有所不同,它只需要一個(gè)類型clazz就可以產(chǎn)生一個(gè)代理對象,而JDK動態(tài)代理要求對象必須實(shí)現(xiàn)接口(三個(gè)參數(shù)的第二個(gè)參數(shù)),cglib則對此沒有要求。
          public?class?Client?{

          ????public?static?void?main(String[]?args)?{
          ????????FangDongCglibProxy?fangDongCglibProxy?=?new?FangDongCglibProxy();
          ????????FangDong?fangDong?=?(FangDong)fangDongCglibProxy.creatProxyedObj(FangDong.class);
          ????????fangDong.hire("我有130平大房子出租~~");
          ????}
          }

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

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人妻夜夜添夜夜无码精品 | 影音先锋乱伦电影 | 精品久久2024 | 欧美精品一区二区三区成人片在线 | 久久人97 |