国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - JAVA代理,靜態,動態詳解

JAVA代理,靜態,動態詳解

2021-12-23 12:52張小馳出沒 Java教程

這篇文章主要介紹了Java靜態代理和動態代理總結,非常不錯,具有參考借鑒價值,需要的朋友可以參考下,希望能夠給你帶來幫助

代理

其他對象提供一種代理以控制這個對象的訪問,在某些情況下一個對象不能直接訪問那個對象時,代理就起到了客戶端和被代理對象 (委托類) 中介作用。

按照代理的創建時期,代理類可以分為兩種:

靜態:由程序員創建代理類或特定工具自動生成源代碼再對其編譯。在程序運行前代理類的.class文件就已經存在了。

動態:在程序運行時運用反射機制動態創建而成。

靜態代理

JAVA代理,靜態,動態詳解

Subject: 代理類和被代理類實現同樣的接口

Proxy:代理類,里面有被代理類,具體邏輯委托被代理類進行處理

RealSubject:被代理類,可以在其內做一些訪問權限控制,額外的業務處理

Client:看到的是代理類,并不知道具體處理業務邏輯的類,降低耦合性

代碼實現

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

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

UserDAOImpl 被代理類(RealSubject)

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

ProxyByInterface 代理類,通過實現接口方式實現代理方式(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 代理類,通過繼承被代理類實現的代理方式(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);
  }
}

獲取代理對象客戶端(Client)

public class Client {
  public static void main(String[] args) {
      ProxyDaoImpl proxyDao = new ProxyDaoImpl();
      //和被代理類實現同個接口方式進行代理
      ProxyByInterface proxyByInterface = new ProxyByInterface(proxyDao);
      proxyByInterface.insert("zc-Interface");
      //通過繼承被代理類方式進行代理
      ProxyByExtend proxyByExtend = new ProxyByExtend(proxyDao);
      proxyByExtend.insert("zc-Extend");
  }
}

JAVA代理,靜態,動態詳解

好處:

可以不用動原來類的邏輯,再次增加一些功能,符合開閉原則。

真正的業務還是交給被代理對象處理的,無須修改原來的類就可以使用代理進行實現。

缺點:

出現了大量的代碼重復。如果接口增加一個方法,除了所有實現類需要實現這個方法外,所有代理類也需要實現此方法。增加了代碼維護的復雜度。

代理對象只服務于一種類型的對象,如果要服務多類型的對象。勢必要為每一種對象都進行代理,靜態代理在程序規模稍大時就無法勝任了。

動態代理

JDK動態代理

Jdk動態代理,針對的是實現接口的類

要求目標對象必須實現接口,因為它創建代理對象的時候是根據接口創建的。被代理對象可以可以實現多個接口,創建代理時指定創建某個接口的代理對象就可以調用該接口定義的方法了。

需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 類的支持

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

代碼實現

NameDao 姓名-接口(Subject)

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

AgeDao 年齡-接口(Subject)

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

NameAndAgeDaoImpl 姓名、年齡實現類(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,對接口提供的方法進行增強(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));
      //執行目標方法對象
      Object result = method.invoke(target, args);
      System.out.println("----------after----------");
      return result;
  }
}

ProxyFactory 代理工廠

public class ProxyFactory {
  public static Object getProxy(Object proxyObj) {
      /**
       * loader 指定加載jvm運行時動態生成的代理對象的加載器
       * interface 真實對象實現的所有接口
       * h 實現InvocationHandler接口對象
       */
    // 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代理,靜態,動態詳解

思考 為什么需要 實現接口的類,而不是 類

main函數中,運行該語句:

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 類:

JAVA代理,靜態,動態詳解

會發現他已經繼承了 Proxy , 之后才是創建的一個(多個)接口;而由于java是 單繼承、多接口 的特性,所以JDK動態代理,需要實現接口的類。

CGLib動態代理

CGLIB實現動態代理,并不要求被代理類必須實現接口,底層采用asm字節碼生成框架生成代理類字節碼(該代理類繼承了被代理類)。

所以被代理類一定不能定義為final class并且對于final 方法不能被代理。

實現需要

//MethodInterceptor接口的intercept方法
/**
*obj 代理對象
*method 委托類方法,被代理對象的方法字節碼對象
*arg 方法參數
*MethodProxy 代理方法MethodProxy對象,每個方法都會對應有這樣一個對象 
*/
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy)
Ehancer enhancer = new Enhancer() //Enhancer為字節碼增強器,很方便對類進行擴展
enhancer.setSuperClass(被代理類.class);
enhancer.setCallback(實現MethodInterceptor接口的對象)
enhancer.create()//返回代理對象,是被代理類的子類

代碼實現

UserDaoImpl 用戶實現類(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代理類(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);
      //執行目標方法對象
      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代理,靜態,動態詳解

思考

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

1.Method method 是被代理對象的方法字節碼對象。

2.MethodProxy methodProxy 是代理對象的方法字節碼對象。

使用 MethodProxy 的好處:

不需要給代理對象傳入被代理對象,效率更高。不會出現死循環的問題。

第一點查看代碼就可以看出,對第二點進行講解:

如何出現死循環的現象:

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

原因:代理對象方法的時候,都會經過攔截器方法。因此,如果在攔截器中再調用代理對象的方法,就會再次進入攔截器,這樣就形成了死循環。

**invokeSuper()**方法,可以使用代理對象父類的方法(就是被代理對象)而不必經過攔截器-----詳情可以學習:《類加載機制》、《雙親委派模型》

 

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注服務器之家的更多內容!

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

延伸 · 閱讀

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

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

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

    littleschemer13532021-05-16
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

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

    Java使用SAX解析xml的示例

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

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

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
主站蜘蛛池模板: 日日精品| 日韩操bb | 免费看黄色一级 | 99久久婷婷国产综合精品电影 | 日韩福利一区二区 | 91在线免费观看 | 亚洲依人 | 日韩视频在线观看一区 | 中文字幕在线三区 | 激情综合网址 | 日本在线视频观看 | 天天操一操 | 黄站免费 | 精品国产子伦久久久久久小说 | 国产精品极品美女在线观看免费 | 在线日韩 | 欧美在线视频网 | 美女黄网 | 天天干天天操天天射 | 亚洲视频欧美视频 | 一个色综合色 | 91九色在线 | 欧洲美女性开放视频 | 亚洲视频免费 | 亚洲精品在线视频 | 黄色电影免费在线观看 | 国产乱轮| av一区二区在线观看 | 国产精品乱码人人做人人爱 | 久久免费看少妇a高潮一片黄特 | 亚洲性网 | 成人免费在线观看 | 精品久久国产老人久久综合 | 成人1区2区 | a黄视频| 国产精品久久久久久久久久免费看 | 懂色av中文一区二区三区天美 | 狠狠综合久久av一区二区老牛 | 久久国 | av片在线看 | 欧美日韩在线免费观看 |