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

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

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

服務器之家 - 編程語言 - Java教程 - Java中的代理模式詳解及實例代碼

Java中的代理模式詳解及實例代碼

2020-08-03 15:20java教程網 Java教程

這篇文章主要介紹了Java中的代理模式詳解及實例代碼的相關資料,這里附有實例代碼,需要的朋友可以參考下

java 代理模式詳解

前言:

在某些情況下,一個客戶不想或者不能直接引用一個對象,此時可以通過一個稱之為“代理”的第三者來實現間接引用。代理對象可以在客戶端和目標對象之間起到 中介的作用,并且可以通過代理對象去掉客戶不能看到 的內容和服務或者添加客戶需要的額外服務。

簡單來說代理模式就是通過一個代理對象去訪問一個實際對象,并且可以像裝飾模式一樣給對象添加一些功能。

靜態代理

所謂靜態代理即在程序運行前代理類就已經存在,也就是說我們編寫代碼的時候就已經把代理類的代碼寫好了,而動態代理則是在程序運行時自動生成代理類。

描述起來太過抽象,看一下代碼就明白是怎么回事了

main

?
1
2
3
4
5
6
7
8
9
public class Main {
 
  public static void main(String[] args) {
    Water water = new Water();
    WaterProxy waterProxy = new WaterProxy(water);
    waterProxy.drink();
  }
 
}

接口

?
1
2
3
4
//代理類與被代理類共同實現的接口
public interface Drink {
  void drink();
}

被代理類

?
1
2
3
4
5
6
7
8
9
//被代理的類
public class Water implements Drink {
 
  @Override
  public void drink() {
    System.out.println("drink water");
  }
 
}

代理類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//代理類
//與被代理類實現同一個接口
public class DrinkProxy implements Drink {
  
  private Drink drinkImpl;
  
  //通過構造函數傳入Water對象
  public DrinkProxy(Drink drinkImpl) {
    this.drinkImpl = drinkImpl;
  }
  
  @Override
  public void drink() {
    //在執行被代理對象的方法前做一些事情
    System.out.println("before drink");
    //執行被代理對象的方法
    drinkImpl.drink();
    //在執行被代理對象的方法后做一些事
    System.out.println("after drink");
  }
 
}

執行結果

?
1
2
3
before drink
drink water
after drink

動態代理

有時候我們只想改變代理類所代理的類,但是代理對象執行實際對象的方法前后所做的事情是一樣的,正所謂鐵打的代理類,流水的被代理類。而采用靜態代理就只能代理實現了同一接口的類,如果要代理任意類則必須寫很多重復的代理類。此時我們可以采用動態代理,Java已經為實現動態代理提供了一套比較方便的工具。

java.lang.reflect.Proxy類中可以動態生成代理對象的方法

?
1
2
3
4
5
6
7
8
9
10
/**
   *返回實現了指定接口的對象,調用代理對象的方法會調用
   *InvocationHandler的invoke方法
   *
   * @param  loader 獲取代理類所使用的類加載器
   * @param  interfaces 代理類所要實現的接口
   * @param  h 實現了InvocationHandler接口的對象
   * @return 代理對象
   */
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

InvocationHandler接口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 *每個代理類都有一個關聯的InvocationHandler
 *當代理對象執行一個方法的時候會直接執行invoke方法
 */
public interface InvocationHandler {
 
  /**
   * @param  調用該方法的代理對象
   * @param  method 代理對象所調用的方法
   * @param  args 調用的方法的參數
   * @return 調用的方法的返回值
   */
  public Object invoke(Object proxy, Method method, Object[] args)
}

描述總是比較抽象,還是看實際例子比較好理解

例子

InvocationHandler接口的實現類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class CommonInvocationHandler implements InvocationHandler {
  
  //被代理的對象
  private Object proxied;
  
  public CommonInvocationHandler(Object proxied) {
    this.proxied = proxied;
  }
  
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //在調用被代理對象的方法前做一些事情
    System.out.println("before doing something");
    //調用被代理對象的方法
    Object result = method.invoke(proxied, args);
    //在調用被代理對象的方法后做一些事情
    System.out.println("after doing something");;
    return result;
  }
 
}

Main

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Main {
 
  public static void main(String[] args) {
    //被代理的對象
    Water water = new Water();
    //動態獲取代理對象
    Drink waterProxy =
        (Drink) Proxy.newProxyInstance(water.getClass().getClassLoader(),
            water.getClass().getInterfaces(),
            new CommonInvocationHandler(water));
    //通過代理對象調用方法
    waterProxy.drink();
  }
 
}

輸出結果

?
1
2
3
before doing something
drink water
after doing something

也可以不要具體的被代理對象,但是必須有相應的接口(沒有實現接口的類可以使用cglib實現動態代理)才可以動態獲取代理對象。像最近比較火的Retrofit就直接通過聲明好的接口使用動態代理進行網絡請求。

例子

簡單的模擬一下retrofit

POST注解

?
1
2
3
4
5
6
//Post請求注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
 String value() default "";
}

Query注解

?
1
2
3
4
5
6
//Post請求注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
 String value() default "";
}

Service接口

?
1
2
3
4
5
6
7
public interface Service {
  //用POST注解聲明請求的方式和相對路徑
  @POST("/login")
  //@Query注解聲明請求的參數名
  void login(@Query("username")String username,
      @Query("password")String password);
}

Main

?
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
public class Main {
 
  public static void main(String[] args) {
    // 動態獲取Service接口的代理
    Service service = (Service) Proxy.newProxyInstance(Service.class.getClassLoader(),
        new Class[] { Service.class }, new InvocationHandler() {
 
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // 通過注解獲取請求的相對路徑
            String retativePath = ((POST) method.getAnnotations()[0]).value();
            System.out.println("relative path: " + retativePath);
            // 獲取參數的注解
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            // 通過參數的注解獲取請求參數
            for (int i = 0; i < parameterAnnotations.length; i++) {
              if (parameterAnnotations[i].length != 0) {
                for (int j = 0; j < parameterAnnotations[i].length; j++) {
                  Query query = (Query) parameterAnnotations[i][j];
                  System.out.println(query.value() + ": " + args[i].toString());
                }
              }
            }
            return null;
          }
        });
    // 調用代理對象的方法
    service.login("hello", "world");
  }
 
}

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 娇妻与老头绿文小说系列 | 日本黄大片影院一区二区 | 国产1区二区 | 99re8在这里只有精品23 | 紧身短裙女教师波多野 | 亚洲精品一区二区三区在线观看 | 啊好痛嗯轻一点免费 | 深夜激情网站 | 成人综合婷婷国产精品久久免费 | 男男调教打屁股 | 操大爷影院 | 乌克兰粉嫩摘花第一次 | 91精品国产综合久久消防器材 | 久久香蕉电影 | 亚洲视频在线观看免费 | 激情综合| 日韩大片免费看 | 男女18一级大黄毛片免 | 波多野结中文字幕在线69视频 | 亚洲系列国产系列 | 免费在线中文字幕 | 欧美国产在线 | 久久AV国产麻豆HD真实 | 青青久在线视频免费观看 | 91亚洲精品第一综合不卡播放 | 国产精品久久一区 | 国产精品国产三级国产专区不 | 亚洲免费视 | 情趣内衣在线观看 | 国产草 | 国产高清在线精品一区 | 不卡视频一区二区 | 草逼网站视频 | 午夜爱爱片 | 国产精品一级香蕉一区 | 香蕉精品视频 | yellow视频在线观看 | 男女肉粗暴进来下面好紧 | 四虎1515hhcom | 亚洲一区 在线播放 | 国产特级 |