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

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

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

服務器之家 - 編程語言 - Java教程 - Java設計模式之動態代理

Java設計模式之動態代理

2021-07-02 14:59Haozz_1994 Java教程

今天小編就為大家分享一篇關于Java設計模式之動態代理,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧

動態代理的意義在于生成一個占位(又稱代理對象),來代理真實對象,從而控制真實對象的訪問。

我們首先來談談什么是代理模式。假設客戶帶著需求去找公司,顯然不會直接和軟件工程師談,而是和商務談,此時客戶會認為商務就代表公司,客戶是通過商務去訪問軟件工程師的。我們就可以認為商務(代理對象)代理了軟件工程師(真實對象),因此,代理的作用就是,在真實對象訪問之前或者之后加入對應的邏輯,或者根據其他規則控制是否使用真實對象。

商務和軟件工程師是代理和被代理的關系,客戶是通過商務去訪問軟件工程師的。此時客戶就是程序中的調用者,商務就是代理對象,軟件工程師就是真實對象。我們需要在調用者調用對象之前產生一個代理對象,而這個代理對象需要和真實對象建立代理關系,所以代理必須分為兩個步驟:

  • 代理對象和真實對象建立代理關系
  • 實現代理對象的代理邏輯方法

在java中有多種動態代理技術,比如jdk、cglib、javassist、asm,其中最常用的動態代理技術有兩種:一種是jdk動態代理,這是jdk自帶的功能;另一種是cglib,這是第三方提供的一個技術。目前,spring常用jdk和cglib,而mybatis還使用了javassist。(cglib的底層原理是asm)

本文只討論兩種最常用的動態代理技術:jdk和cglib。在jdk動態代理中必須使用接口,而cglib不需要,所以使用cglib會更簡單一點。下面依次討論這兩種技術。

一.jdk動態代理

jdk動態代理是java.lang.reflect.*包提供的方式。它必須借助一個接口才能產生代理對象,所以先定義接口helloworld:

?
1
2
3
public interface helloworld {
  void sayhelloworld();
}

然后提供實現類helloworldimpl來實現接口:

?
1
2
3
4
5
6
public class helloworldimpl implements helloworld {
  @override
  public void sayhelloworld(){
    system.out.println("hello world");
  }
}

這是最簡答的java接口和實現類的關系,此時可以開始動態代理了。按照我們之前的分析,先要建立代理對象和真實對象的關系,然后實現代理邏輯,所以一共分為兩個步驟。在jdk動態代理中,代理邏輯類必須去實現java.lang.reflect.invocationhandler接口,它定義了一個invoke方法,并提供接口數組用于下掛代理對象。我們自己定義一個jdk動態代理的類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class myjdkproxyexample implements invocationhandler{
  /**
   * @description 真實對象
   **/
  private object target = null;
  /**
   * @author haozz
   * @date 2018-05-21 10:54
   * @param target 真實對象
   * @return 代理對象
   * @throws
   * @description 建立代理對象和真實對象的代理關系,并返回代理對象
   **/
  public object getproxy(object target) {
    this.target = target;
    return proxy.newproxyinstance(target.getclass().getclassloader(),target.getclass().getinterfaces(),this);
  }
  /**
   * @author haozz
   * @date 2018-05-21 11:09
   * @param proxy 代理對象
   * @param method 當前調度方法
   * @param args 當前方法參數
   * @return 代理結果
   * @throws throwable 異常
   * @description 代理方法邏輯
   **/
  @override
  public object invoke(object proxy, method method,object [] args) throws throwable{
    system.out.println("進入代理邏輯方法");
    system.out.println("在調度真實對象之前的服務");
    object obj = method.invoke(target,args);//相當于調用sayhelloworld方法
    system.out.println("在調度真實對象之后的服務");
    return obj;
  }
}

第一步,通過getproxy()方法建立代理對象和真實對象的關系,并返回代理對象。首先用類的屬性target保存了真實對象,然后通過proxy.newproxyinstance()方法建立并生成代理對象,該方法中包含3個參數:

  • 第1個是類加載器,這里采用了target本身的類加載器;
  • 第2個是把生成的動態代理對象下掛在哪些接口下,這個寫法就是放在target實現的接口下。helloworldimpl對象的接口顯然就是helloworld,代理對象可以這樣聲明:helloworld proxy = xxxx;;
  • 第3個是定義實現方法邏輯的代理類,this表示當前對象,它必須實現invocationhandler接口的invoke方法,它就是代理邏輯方法的現實方法。

第二步,通過invoke方法實現代理邏輯方法。invoke方法的3個參數:

  • proxy,代理對象,就是getproxy方法生成的對象;
  • method,當前調度的方法;
  • args,當前調度方法的參數。

當我們使用了代理對象調度方法后,它就會進入到invoke方法里面。

?
1
object obj = method.invoke(target,args);

這行代碼相當于調度真實對象的方法,只是通過反射實現。類比前面的例子,proxy相當于商務,target相當于軟件工程師,getproxy方法就是建立商務和軟件工程師之間的代理關系,invoke方法就是商務邏輯。

測試jdk動態代理:

?
1
2
3
4
5
6
7
8
@test
public void testjdkproxy(){
  myjdkproxyexample jdkproxy = new myjdkproxyexample();
  //綁定關系,因為掛在接口helloworld下,所以聲明代理對象helloworld proxy
  helloworld proxy = (helloworld) jdkproxy.getproxy(new helloworldimpl());
  //此時helloworld對象已經是一個代理對象,它會進入代理的邏輯方法invoke里
  proxy.sayhelloworld();
}

首先通過getproxy方法綁定了代理關系,然后在代理對象調度sayhelloworld方法時進入了代理的邏輯,測試結果如下:

進入代理邏輯方法
在調度真實對象之前的服務
hello world
在調度真實對象之后的服務

此時,在調度打印hello world之前和之后都可以加入相關的邏輯,甚至可以不調度hello world的打印。

個人小結:jdk動態代理要求真實對象和代理對象之間是實現類和接口的關系,創建一個代理邏輯類實現invocationhandler接口,其中getproxy方法用于生成代理對象,然后重寫invoke方法。

二.cglib動態代理

jdk動態代理必須提供接口才能使用,在一些不能提供接口的環境中,只能采用其他第三方技術,比如cglib動態代理,這里提供cglib動態代理的相關jar包,供學習和測試使用。它的優勢在于不需要提供接口,只要一個非抽象類就能實現動態代理。

cglib原理:動態生成一個要代理類的子類,子類重寫要代理的類的所有不是final的方法。在子類中采用方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。它比使用java反射的jdk動態代理要快。cglib底層:使用字節碼處理框架asm,來轉換字節碼并生成新的類。不鼓勵直接使用asm,因為它要求你必須對jvm內部結構包括class文件的格式和指令集都很熟悉。cglib缺點:對于final方法,無法進行代理。cglib廣泛地被許多aop的框架使用,例如spring aop和dynaop。hibernate使用cglib來代理單端single-ended(多對一和一對一)關聯。

我們以下面這個類為例:

?
1
2
3
4
5
public class reflectserviceimpl {
  public void sayhello(string name){
    system.out.println("hello "+name);
  }
}

它不存在實現任何接口,所以不能使用jdk動態代理,這里采用cglib動態代理技術:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class mycglibproxyexample implements methodinterceptor{
  /**
   * @author haozz
   * @date 2018-05-21 15:11
   * @param cls class類
   * @return class類的cglib對象
   * @throws
   * @description 生成cglib代理對象
   **/
  public object getproxy(class cls){
    //cglib增強類對象
    enhancer enhancer = new enhancer();
    //設置增強類型
    enhancer.setsuperclass(cls);
    //定義代理邏輯對象為當前對象,要求當前對象實現methodinterceptor方法
    enhancer.setcallback(this);
    //生成并返回代理對象
    return enhancer.create();
  }
  /**
   * @author haozz
   * @date 2018-05-21 15:17
   * @param proxy 代理對象
   * @param method 目標方法
   * @param args 目標方法參數
   * @param methodproxy 方法代理
   * @return 代理邏輯返回
   * @throws throwable 異常
   * @description 代理邏輯方法
   **/
  @override
  public object intercept(object proxy, method method, object[] args, methodproxy methodproxy)throws throwable{
    system.out.println("調用真實對象前");
    //cglib反射調用真實對象方法
    object result = methodproxy.invokesuper(proxy,args);
    system.out.println("調用真實對象后");
    return result;
  }
}

這里用了cglib的加強者enhancer(net.sf.sglib.proxy.enhancer),通過設置超類的方法(setsuperclass),然后通過setcallback方法設置哪個類為它的代理類。其中,參數this表示當前對象,那就要求用this這個對象實現接口methodinterceptor(net.sf.sglib.proxy.methodinterceptor)的方法intercept,然后返回代理對象。那么此時當前類的intercept方法就是其代理邏輯方法,其參數內容見代碼注解,我們在反射真實對象方法前后進行了打印,cglib是通過如下代碼完成的:

?
1
object result = methodproxy.invokesuper(proxy,args);

測試一下cglib動態代理:

?
1
2
3
4
5
6
@test
public void testcglibproxy(){
  mycglibproxyexample cglibproxy = new mycglibproxyexample();
  reflectserviceimpl obj = (reflectserviceimpl) cglibproxy.getproxy(reflectserviceimpl.class);
  obj.sayhello("haozz");
}

得到結果:

調用真實對象前
hello haozz
調用真實對象后

個人小結:cglib動態代理相對簡單一些,通過字節碼技術為需要代理的類生成一個子類,它不需要提供接口,只需寫一個代理邏輯類并實現methodinterceptor接口,其中getproxy方法用于生成代理對象,然后重寫intercept方法即可。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對服務器之家的支持。如果你想了解更多相關內容請查看下面相關鏈接

原文鏈接:https://blog.csdn.net/hz_940611/article/details/80388691

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 午夜精品久久久久久久久久久久 | 国产午夜精品久久久久久久 | 国产 日韩 欧美 中文 在线播放 | 国产丝袜在线 | 日韩一区二区在线观看 | 成人久久18免费观看 | 在线欧美一区 | 久久国产精品视频 | 国产成人在线看 | 日韩视频在线一区二区 | 日韩高清不卡一区二区三区 | 午夜寂寞少妇aaa片毛片 | 一级片免费视频 | 欧美在线高清 | 精品中文一区 | 亚洲天堂中文字幕 | 亚洲精品一区二区三区蜜桃久 | 成人一级片 | 黄色a站 | 亚洲视频第一页 | 狠狠色综合网站久久久久久久 | 欧美日韩中文字幕在线 | 欧美精品一二区 | 日韩有码视频在线 | 情一色一乱一欲一区二区 | 精品一区二区三区在线观看 | 日韩黄色片免费看 | 最好的2019中文大全在线观看 | 色婷婷一区二区三区 | 久久国产精品免费一区二区三区 | 国产精品国产精品国产专区不片 | 视频一区二区三区中文字幕 | 国产精品国产精品国产专区不片 | 日日操操 | 欧美精品91 | 天天干人人 | 久久精品99视频 | 欧美福利在线观看 | 日韩精品一区二区三区四区 | 在线观看黄 | 国产精品久久久久久久一区探花 |