激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

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

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

服務器之家 - 編程語言 - Java教程 - Java的三種代理模式簡述

Java的三種代理模式簡述

2021-12-23 13:23閃客sun Java教程

這篇文章主要簡述Java的三種代理模式,java的代理模式主要包括靜態代理、動態代理、Cglib代理,感興趣的小伙伴可以參考下面文章的具體內容

一、代理模式是什么

代理模式是一種設計模式,簡單說即是在不改變源碼的情況下,實現對目標對象的功能擴展。

比如有個歌手對象叫Singer,這個對象有一個唱歌方法叫sing()。

?
1
2
3
4
5
1 public class Singer{
2     public void sing(){
3         System.out.println("唱一首歌");
4    
5 }

假如你希望,通過你的某種方式生產出來的歌手對象,在唱歌前后還要想觀眾問好和答謝,也即對目標對象Singer的sing方法進行功能擴展

?
1
2
3
4
5
1 public void sing(){
2     System.out.println("向觀眾問好");
3     System.out.println("唱一首歌");
4     System.out.println("謝謝大家");
5

但是往往你又不能直接對源代碼進行修改,可能是你希望原來的對象還保持原來的樣子,又或許你提供的只是一個可插拔的插件,甚至你有可能都不知道你要對哪個目標對象進行擴展。這時就需要用到java的代理模式了。網上好多用生活中的經理人的例子來解釋“代理”,看似通俗易懂,但我覺得不適合程序員去理解。程序員應該從代碼的本質入手。

二、Java的三種代理模式

想要實現以上的需求有三種方式,這一部分我們只看三種模式的代碼怎么寫,先不涉及實現原理的部分。

1.靜態代理

?
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
1 public interface ISinger {
 2     void sing();
 3 }
 4
 5 /**
 6  *  目標對象實現了某一接口
 7  */
 8 public class Singer implements ISinger{
 9     public void sing(){
10         System.out.println("唱一首歌");
11    
12 }
13
14 /**
15  *  代理對象和目標對象實現相同的接口
16  */
17 public class SingerProxy implements ISinger{
18     // 接收目標對象,以便調用sing方法
19     private ISinger target;
20     public UserDaoProxy(ISinger target){
21         this.target=target;
22     }
23     // 對目標對象的sing方法進行功能擴展
24     public void sing() {
25         System.out.println("向觀眾問好");
26         target.sing();
27         System.out.println("謝謝大家");
28     }
29 }

測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
1 /**
 2  * 測試類
 3  */
 4 public class Test {
 5     public static void main(String[] args) {
 6         //目標對象
 7         ISinger target = new Singer();
 8         //代理對象
 9         ISinger proxy = new SingerProxy(target);
10         //執行的是代理的方法
11         proxy.sing();
12     }
13 }

  總結:其實這里做的事情無非就是,創建一個代理類SingerProxy,繼承了ISinger接口并實現了其中的方法。只不過這種實現特意包含了目標對象的方法,正是這種特征使得看起來像是“擴展”了目標對象的方法。假使代理對象中只是簡單地對sing方法做了另一種實現而沒有包含目標對象的方法,也就不能算作代理模式了。所以這里的包含是關鍵。

  缺點:這種實現方式很直觀也很簡單,但其缺點是代理對象必須提前寫出,如果接口層發生了變化,代理對象的代碼也要進行維護。如果能在運行時動態地寫出代理對象,不但減少了一大批代理類的代碼,也少了不斷維護的煩惱,不過運行時的效率必定受到影響。這種方式就是接下來的動態代理。

2.動態代理(也叫JDK代理)

跟靜態代理的前提一樣,依然是對Singer對象進行擴展

?
1
2
3
4
5
6
7
8
9
10
11
12
1 public interface ISinger {
 2     void sing();
 3 }
 4
 5 /**
 6  *  目標對象實現了某一接口
 7  */
 8 public class Singer implements ISinger{
 9     public void sing(){
10         System.out.println("唱一首歌");
11    
12 }

這回直接上測試,由于java底層封裝了實現細節(之后會詳細講),所以代碼非常簡單,格式也基本上固定。

調用Proxy類的靜態方法newProxyInstance即可,該方法會返回代理類對象

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
接收的三個參數依次為:

  • ClassLoader loader:指定當前目標對象使用類加載器,寫法固定
  • Class<?>[] interfaces:目標對象實現的接口的類型,寫法固定
  • InvocationHandler h:事件處理接口,需傳入一個實現類,一般直接使用匿名內部類

測試代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1 public class Test{
 2     public static void main(String[] args) {
 3   Singer target = new Singer();
 4         ISinger proxy  = (ISinger) Proxy.newProxyInstance(
 5                 target.getClass().getClassLoader(),
 6                 target.getClass().getInterfaces(),
 7                 new InvocationHandler() {
 8                     @Override
 9                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
10                         System.out.println("向觀眾問好");
11                         //執行目標對象方法
12                         Object returnValue = method.invoke(target, args);
13                         System.out.println("謝謝大家");
14                         return returnValue;
15                     }
16                 });
17         proxy.sing();
18     }
19 }

總結:以上代碼只有標黃的部分是需要自己寫出,其余部分全都是固定代碼。由于java封裝了newProxyInstance這個方法的實現細節,所以使用起來才能這么方便,具體的底層原理將會在下一小節說明。

缺點:可以看出靜態代理和JDK代理有一個共同的缺點,就是目標對象必須實現一個或多個接口,加入沒有,則可以使用Cglib代理。

3.Cglib代理

前提條件:

  • 需要引入cglib的jar文件,由于Spring的核心包中已經包括了Cglib功能,所以也可以直接引入spring-core-3.2.5.jar
  • 目標類不能為final
  • 目標對象的方法如果為final/static,那么就不會被攔截,即不會執行目標對象額外的業務方法
?
1
2
3
4
5
6
7
8
9
1 /**
2  * 目標對象,沒有實現任何接口
3  */
4 public class Singer{
5
6     public void sing() {
7         System.out.println("唱一首歌");
8     }
9 }
?
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
1 /**
 2  * Cglib子類代理工廠
 3  */
 4 public class ProxyFactory implements MethodInterceptor{
 5     // 維護目標對象
 6     private Object target;
 7
 8     public ProxyFactory(Object target) {
 9         this.target = target;
10     }
11
12     // 給目標對象創建一個代理對象
13     public Object getProxyInstance(){
14         //1.工具類
15         Enhancer en = new Enhancer();
16         //2.設置父類
17         en.setSuperclass(target.getClass());
18         //3.設置回調函數
19         en.setCallback(this);
20         //4.創建子類(代理對象)
21         return en.create();
22     }
23
24     @Override
25     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
26         System.out.println("向觀眾問好");
27         //執行目標對象的方法
28         Object returnValue = method.invoke(target, args);
29         System.out.println("謝謝大家");
30         return returnValue;
31     }
32 }

這里的代碼也非常固定,只有標黃部分是需要自己寫出

測試

?
1
2
3
4
5
6
7
8
9
10
11
12
13
1 /**
 2  * 測試類
 3  */
 4 public class Test{
 5     public static void main(String[] args){
 6         //目標對象
 7         Singer target = new Singer();
 8         //代理對象
 9         Singer proxy = (Singer)new ProxyFactory(target).getProxyInstance();
10         //執行代理對象的方法
11         proxy.sing();
12     }
13 }

總結:三種代理模式各有優缺點和相應的適用范圍,主要看目標對象是否實現了接口。以Spring框架所選擇的代理模式舉例

  • 在Spring的AOP編程中:
  • 如果加入容器的目標對象有實現接口,用JDK代理
  • 如果目標對象沒有實現接口,用Cglib代理

到此這篇關于Java的三種代理模式簡述的文章就介紹到這了,更多相關Java的三種代理模式內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/flashsun/p/7286475.html

延伸 · 閱讀

精彩推薦
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

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

    littleschemer13532021-05-16
  • Java教程Java8中Stream使用的一個注意事項

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

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

    阿杜7482021-02-04
  • Java教程20個非常實用的Java程序代碼片段

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

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

    lijiao5352020-04-06
  • Java教程小米推送Java代碼

    小米推送Java代碼

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

    富貴穩中求8032021-07-12
  • Java教程升級IDEA后Lombok不能使用的解決方法

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

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

    程序猿DD9332021-10-08
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

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

    Java教程網2942020-09-17
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

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

    大行者10067412021-08-30
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

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

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

    spcoder14552021-10-18
主站蜘蛛池模板: 一级电影免费 | 日韩av毛片免费观看 | 成人爱爱电影 | 久久久久久片 | 国产九色视频在线观看 | 本站只有精品 | 91精品国产综合久久青草 | 55夜色66夜色国产精品视频 | 中文字幕一区久久 | 羞羞网站| 视频一区国产精品 | 一区二区三区日韩视频在线观看 | av在线免费观看国产 | 欧美久久久一区二区三区 | 久久精品一级 | 天天操天天碰 | 91视频久久| 97超级碰碰人国产在线观看 | 日本高清黄色片 | 91成人午夜性a一级毛片 | 九九热视频免费观看 | 国产精品成人亚洲一区二区 | 毛片免费看网站 | 中文字幕免费在线观看视频 | 精品国产一区在线 | 欧美精品毛片 | 91超视频 | 久久99精品久久久久久秒播放器 | 男女生羞羞视频网站在线观看 | 精品一区二区中文字幕 | 久草资源在线观看 | av在线免费电影 | 欧美日韩精品一区二区三区不卡 | 免费国产精品视频 | 日本在线观看视频网站 | 亚洲成人网一区 | 成人一级视频在线观看 | 天海翼四虎精品正在播放 | wwwxxx国产 | 国产精品一区二区三区在线看 | 91成人免费看 |