一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - JAVA代理,靜態(tài),動(dòng)態(tài)詳解

JAVA代理,靜態(tài),動(dòng)態(tài)詳解

2021-12-23 12:52張小馳出沒(méi) Java教程

這篇文章主要介紹了Java靜態(tài)代理和動(dòng)態(tài)代理總結(jié),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下,希望能夠給你帶來(lái)幫助

代理

其他對(duì)象提供一種代理以控制這個(gè)對(duì)象的訪(fǎng)問(wèn),在某些情況下一個(gè)對(duì)象不能直接訪(fǎng)問(wèn)那個(gè)對(duì)象時(shí),代理就起到了客戶(hù)端和被代理對(duì)象 (委托類(lèi)) 中介作用。

按照代理的創(chuàng)建時(shí)期,代理類(lèi)可以分為兩種:

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

動(dòng)態(tài):在程序運(yùn)行時(shí)運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。

靜態(tài)代理

JAVA代理,靜態(tài),動(dòng)態(tài)詳解

Subject: 代理類(lèi)和被代理類(lèi)實(shí)現(xiàn)同樣的接口

Proxy:代理類(lèi),里面有被代理類(lèi),具體邏輯委托被代理類(lèi)進(jìn)行處理

RealSubject:被代理類(lèi),可以在其內(nèi)做一些訪(fǎng)問(wèn)權(quán)限控制,額外的業(yè)務(wù)處理

Client:看到的是代理類(lèi),并不知道具體處理業(yè)務(wù)邏輯的類(lèi),降低耦合性

代碼實(shí)現(xiàn)

UserDAO 代理和被代理的公共的接口(Subject)

public interface ProxyDao {
  boolean insert(String name);
}

UserDAOImpl 被代理類(lèi)(RealSubject)

public class ProxyDaoImpl implements ProxyDao {
  @Override
  public boolean insert(String name) {
      System.out.println("insert name=" + name);
      return true;
  }
}

ProxyByInterface 代理類(lèi),通過(guò)實(shí)現(xiàn)接口方式實(shí)現(xiàn)代理方式(Proxy)

public class ProxyByInterface implements ProxyDao {
  private ProxyDao proxyDao;
  public ProxyByInterface(ProxyDao proxyDao) {
      this.proxyDao = proxyDao;
  }
  @Override
  public boolean insert(String name) {
      System.out.println("before insert by interface");
      return proxyDao.insert(name);
  }
}

ProxyByExtend 代理類(lèi),通過(guò)繼承被代理類(lèi)實(shí)現(xiàn)的代理方式(Proxy)

public class ProxyByExtend extends ProxyDaoImpl{
  private ProxyDaoImpl proxyDao;
  public ProxyByExtend(ProxyDaoImpl proxyDao) {
      this.proxyDao = proxyDao;
  }
  @Override
  public boolean insert(String name) {
      System.out.println("before insert by extend");
      return proxyDao.insert(name);
  }
}

獲取代理對(duì)象客戶(hù)端(Client)

public class Client {
  public static void main(String[] args) {
      ProxyDaoImpl proxyDao = new ProxyDaoImpl();
      //和被代理類(lèi)實(shí)現(xiàn)同個(gè)接口方式進(jìn)行代理
      ProxyByInterface proxyByInterface = new ProxyByInterface(proxyDao);
      proxyByInterface.insert("zc-Interface");
      //通過(guò)繼承被代理類(lèi)方式進(jìn)行代理
      ProxyByExtend proxyByExtend = new ProxyByExtend(proxyDao);
      proxyByExtend.insert("zc-Extend");
  }
}

JAVA代理,靜態(tài),動(dòng)態(tài)詳解

好處:

可以不用動(dòng)原來(lái)類(lèi)的邏輯,再次增加一些功能,符合開(kāi)閉原則。

真正的業(yè)務(wù)還是交給被代理對(duì)象處理的,無(wú)須修改原來(lái)的類(lèi)就可以使用代理進(jìn)行實(shí)現(xiàn)。

缺點(diǎn):

出現(xiàn)了大量的代碼重復(fù)。如果接口增加一個(gè)方法,除了所有實(shí)現(xiàn)類(lèi)需要實(shí)現(xiàn)這個(gè)方法外,所有代理類(lèi)也需要實(shí)現(xiàn)此方法。增加了代碼維護(hù)的復(fù)雜度。

代理對(duì)象只服務(wù)于一種類(lèi)型的對(duì)象,如果要服務(wù)多類(lèi)型的對(duì)象。勢(shì)必要為每一種對(duì)象都進(jìn)行代理,靜態(tài)代理在程序規(guī)模稍大時(shí)就無(wú)法勝任了。

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

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

Jdk動(dòng)態(tài)代理,針對(duì)的是實(shí)現(xiàn)接口的類(lèi)

要求目標(biāo)對(duì)象必須實(shí)現(xiàn)接口,因?yàn)樗鼊?chuàng)建代理對(duì)象的時(shí)候是根據(jù)接口創(chuàng)建的。被代理對(duì)象可以可以實(shí)現(xiàn)多個(gè)接口,創(chuàng)建代理時(shí)指定創(chuàng)建某個(gè)接口的代理對(duì)象就可以調(diào)用該接口定義的方法了。

需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 類(lèi)的支持

//Object proxy:被代理的對(duì)象
//Method method:要調(diào)用的方法
//Object[] args:方法調(diào)用時(shí)所需要參數(shù)
public interface InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
//CLassLoader loader:類(lèi)的加載器
//Class<?> interfaces:得到全部的接口
//InvocationHandler h:得到InvocationHandler接口的子類(lèi)的實(shí)例
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

代碼實(shí)現(xiàn)

NameDao 姓名-接口(Subject)

public interface NameDao {
  public boolean addName(String name);
}

AgeDao 年齡-接口(Subject)

public interface AgeDao {
  public boolean addAge(Integer age);
}

NameAndAgeDaoImpl 姓名、年齡實(shí)現(xiàn)類(lèi)(RealSubject)

public class NameAndAgeDaoImpl implements NameDao,AgeDao {
  @Override
  public boolean addName(String name) {
      System.out.println("NameDaoImpl----->" + name);
      return true;
  }
  @Override
  public boolean addAge(Integer age) {
      System.out.println("AgeDaoImpl----->" + age);
      return true;
  }
}

MyInvocationHandler,對(duì)接口提供的方法進(jìn)行增強(qiáng)(Proxy)

public class MyInvocationHandler implements InvocationHandler {
  private Object target;
  public MyInvocationHandler(Object target) {
      this.target = target;
  }
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("----------before----------");
      System.out.println("Proxy=" + proxy.getClass());
      System.out.println("method=" + method);
      System.out.println("args=" + Arrays.toString(args));
      //執(zhí)行目標(biāo)方法對(duì)象
      Object result = method.invoke(target, args);
      System.out.println("----------after----------");
      return result;
  }
}

ProxyFactory 代理工廠

public class ProxyFactory {
  public static Object getProxy(Object proxyObj) {
      /**
       * loader 指定加載jvm運(yùn)行時(shí)動(dòng)態(tài)生成的代理對(duì)象的加載器
       * interface 真實(shí)對(duì)象實(shí)現(xiàn)的所有接口
       * h 實(shí)現(xiàn)InvocationHandler接口對(duì)象
       */
    // return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(),
    // proxyObj.getClass().getInterfaces(), new MyInvocationHandler(proxyObj));
      return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
              proxyObj.getClass().getInterfaces(), new MyInvocationHandler(proxyObj));
  }
  public static void main(String[] args) {
      NameDao nameDao = (NameDao) getProxy(new NameAndAgeDaoImpl());
      AgeDao ageDao = (AgeDao) getProxy(new NameAndAgeDaoImpl());
      nameDao.addName("zc");
      ageDao.addAge(20);
  }
}

JAVA代理,靜態(tài),動(dòng)態(tài)詳解

思考 為什么需要 實(shí)現(xiàn)接口的類(lèi),而不是 類(lèi)

main函數(shù)中,運(yùn)行該語(yǔ)句:

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
public static void main(String[] args) {
  System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
  NameDao nameDao = (NameDao) getProxy(new NameAndAgeDaoImpl());
  AgeDao ageDao = (AgeDao) getProxy(new NameAndAgeDaoImpl());
  nameDao.addName("zc");
  ageDao.addAge(20);
}

可以查看 $Proxy0 類(lèi):

JAVA代理,靜態(tài),動(dòng)態(tài)詳解

會(huì)發(fā)現(xiàn)他已經(jīng)繼承了 Proxy , 之后才是創(chuàng)建的一個(gè)(多個(gè))接口;而由于java是 單繼承、多接口 的特性,所以JDK動(dòng)態(tài)代理,需要實(shí)現(xiàn)接口的類(lèi)。

CGLib動(dòng)態(tài)代理

CGLIB實(shí)現(xiàn)動(dòng)態(tài)代理,并不要求被代理類(lèi)必須實(shí)現(xiàn)接口,底層采用asm字節(jié)碼生成框架生成代理類(lèi)字節(jié)碼(該代理類(lèi)繼承了被代理類(lèi))。

所以被代理類(lèi)一定不能定義為final class并且對(duì)于final 方法不能被代理。

實(shí)現(xiàn)需要

//MethodInterceptor接口的intercept方法
/**
*obj 代理對(duì)象
*method 委托類(lèi)方法,被代理對(duì)象的方法字節(jié)碼對(duì)象
*arg 方法參數(shù)
*MethodProxy 代理方法MethodProxy對(duì)象,每個(gè)方法都會(huì)對(duì)應(yīng)有這樣一個(gè)對(duì)象 
*/
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy)
Ehancer enhancer = new Enhancer() //Enhancer為字節(jié)碼增強(qiáng)器,很方便對(duì)類(lèi)進(jìn)行擴(kuò)展
enhancer.setSuperClass(被代理類(lèi).class);
enhancer.setCallback(實(shí)現(xiàn)MethodInterceptor接口的對(duì)象)
enhancer.create()//返回代理對(duì)象,是被代理類(lèi)的子類(lèi)

代碼實(shí)現(xiàn)

UserDaoImpl 用戶(hù)實(shí)現(xiàn)類(lèi)(RealSubject)

public class UserDaoImpl {
  public boolean insert(String name) {
      System.out.println("insert name=" + name);
      return true;
  }
  public final boolean insert1(String name) {
      System.out.println("final insert name=" + name);
      return true;
  }
}

CglibProxy CGLIB代理類(lèi)(Proxy)

public class CglibProxy implements MethodInterceptor {
  @Override
  public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
      System.out.println("----------before----------");
      System.out.println("Proxy=" + o.getClass());
      System.out.println("method=" + method);
      System.out.println("args=" + Arrays.toString(objects));
      System.out.println("methodProxy=" + methodProxy);
      //執(zhí)行目標(biāo)方法對(duì)象
      Object result = methodProxy.invokeSuper(o, objects);
      System.out.println("----------after----------");
      return result;
  }
}

ProxyFactory 代理工廠

public class ProxyFactory {
  private static Enhancer enhancer = new Enhancer();
  private static CglibProxy cglibProxy = new CglibProxy();
  public static Object getProxy(Class cls) {
      enhancer.setSuperclass(cls);
      enhancer.setCallback(cglibProxy);
      return enhancer.create();
  }
  public static void main(String[] args) {
      UserDaoImpl userDao = (UserDaoImpl) getProxy(UserDaoImpl.class);
      userDao.insert("zc");
  }
}

JAVA代理,靜態(tài),動(dòng)態(tài)詳解

思考

為什么這里面使用 invokeSuper() ,不使用 invoke()

1.Method method 是被代理對(duì)象的方法字節(jié)碼對(duì)象。

2.MethodProxy methodProxy 是代理對(duì)象的方法字節(jié)碼對(duì)象。

使用 MethodProxy 的好處:

不需要給代理對(duì)象傳入被代理對(duì)象,效率更高。不會(huì)出現(xiàn)死循環(huán)的問(wèn)題。

第一點(diǎn)查看代碼就可以看出,對(duì)第二點(diǎn)進(jìn)行講解:

如何出現(xiàn)死循環(huán)的現(xiàn)象:

	Proxy.newProxyInstance(xxx, xxx,
              new InvocationHandler() {
                  @Override
                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  	...
                    //加入這一句  
                  	proxy.toString();
                  	...
                  }
              });

原因:代理對(duì)象方法的時(shí)候,都會(huì)經(jīng)過(guò)攔截器方法。因此,如果在攔截器中再調(diào)用代理對(duì)象的方法,就會(huì)再次進(jìn)入攔截器,這樣就形成了死循環(huán)。

**invokeSuper()**方法,可以使用代理對(duì)象父類(lèi)的方法(就是被代理對(duì)象)而不必經(jīng)過(guò)攔截器-----詳情可以學(xué)習(xí):《類(lèi)加載機(jī)制》、《雙親委派模型》

 

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注服務(wù)器之家的更多內(nèi)容!

原文鏈接:https://blog.csdn.net/qq_43740362/article/details/120123454

延伸 · 閱讀

精彩推薦
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關(guān)于小米推送Java代碼,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧...

    富貴穩(wěn)中求8032021-07-12
  • Java教程Java8中Stream使用的一個(gè)注意事項(xiàng)

    Java8中Stream使用的一個(gè)注意事項(xiàng)

    最近在工作中發(fā)現(xiàn)了對(duì)于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個(gè)非常重要的注意點(diǎn),所以這篇文章主要給大家介紹了關(guān)于Java8中S...

    阿杜7482021-02-04
  • Java教程xml與Java對(duì)象的轉(zhuǎn)換詳解

    xml與Java對(duì)象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對(duì)象的轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
  • Java教程Java實(shí)現(xiàn)搶紅包功能

    Java實(shí)現(xiàn)搶紅包功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)搶紅包功能,采用多線(xiàn)程模擬多人同時(shí)搶紅包,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java BufferWriter寫(xiě)文件寫(xiě)不進(jìn)去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫(xiě)文件寫(xiě)不進(jìn)去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫(xiě)文件寫(xiě)不進(jìn)去或缺失數(shù)據(jù)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程升級(jí)IDEA后Lombok不能使用的解決方法

    升級(jí)IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級(jí),尋思已經(jīng)有好久沒(méi)有升過(guò)級(jí)了。升級(jí)完畢重啟之后,突然發(fā)現(xiàn)好多錯(cuò)誤,本文就來(lái)介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程20個(gè)非常實(shí)用的Java程序代碼片段

    20個(gè)非常實(shí)用的Java程序代碼片段

    這篇文章主要為大家分享了20個(gè)非常實(shí)用的Java程序片段,對(duì)java開(kāi)發(fā)項(xiàng)目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
主站蜘蛛池模板: 国内精品久久久久久久久 | 鬼畜重口高h合集长短篇 | 国产成人免费片在线视频观看 | 狠狠婷婷综合缴情亚洲 | 香港论理午夜电影网 | 男人操男人 | 免费观看欧美成人h | 国产精品极品 | 奇米激情| 日本暖暖视频在线观看 | 亚洲精品久久久久AV无码 | 成人免费观看网欧美片 | 国产福利在线观看第二区 | 国产va免费精品高清在线 | 国产日韩欧美综合一区二区三区 | 大伊香蕉精品二区视频在线 | 成人一区二区丝袜美腿 | 二次元美女内裤凹陷太深 | 亚洲电影不卡 | 国内激情自拍 | 我要看黄色毛片 | 欧美乱子伦xxxx12在线 | 国产亚洲精品线观看77 | 99九九精品视频 | 午夜亚洲精品久久久久久 | 无遮挡h肉动漫在线观看电车 | 女同69式互添在线观看免费 | 男老头澡堂gay老头456 | 精品福利一区二区免费视频 | 双性总裁被调教1v1 双性双根 | 国产精品麻豆免费版 | 波多野结衣女教师在线观看 | 很黄的网站在线观看 | 四虎comwww最新地址 | 双性太子 | 久久人妻无码毛片A片麻豆 久久热这里只有 精品 | les在宿舍吃她奶 | 国产精品久久久久久影院 | 美女被躁爽死 | 草莓视频在线免费观看 | 亚洲成人免费看 |