欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的代理模式詳解及實(shí)例代碼

 更新時(shí)間:2017年02月04日 16:09:49   投稿:lqh  
這篇文章主要介紹了Java中的代理模式詳解及實(shí)例代碼的相關(guān)資料,這里附有實(shí)例代碼,需要的朋友可以參考下

java 代理模式詳解

前言:

在某些情況下,一個(gè)客戶不想或者不能直接引用一個(gè)對(duì)象,此時(shí)可以通過(guò)一個(gè)稱之為“代理”的第三者來(lái)實(shí)現(xiàn)間接引用。代理對(duì)象可以在客戶端和目標(biāo)對(duì)象之間起到 中介的作用,并且可以通過(guò)代理對(duì)象去掉客戶不能看到 的內(nèi)容和服務(wù)或者添加客戶需要的額外服務(wù)。

簡(jiǎn)單來(lái)說(shuō)代理模式就是通過(guò)一個(gè)代理對(duì)象去訪問(wèn)一個(gè)實(shí)際對(duì)象,并且可以像裝飾模式一樣給對(duì)象添加一些功能。

靜態(tài)代理

所謂靜態(tài)代理即在程序運(yùn)行前代理類就已經(jīng)存在,也就是說(shuō)我們編寫(xiě)代碼的時(shí)候就已經(jīng)把代理類的代碼寫(xiě)好了,而動(dòng)態(tài)代理則是在程序運(yùn)行時(shí)自動(dòng)生成代理類。

描述起來(lái)太過(guò)抽象,看一下代碼就明白是怎么回事了

main

public class Main {

  public static void main(String[] args) {
    Water water = new Water();
    WaterProxy waterProxy = new WaterProxy(water);
    waterProxy.drink();
  }

}

接口

//代理類與被代理類共同實(shí)現(xiàn)的接口
public interface Drink {
  void drink();
}

被代理類

//被代理的類
public class Water implements Drink {

  @Override
  public void drink() {
    System.out.println("drink water");
  }

}

代理類

//代理類
//與被代理類實(shí)現(xiàn)同一個(gè)接口
public class DrinkProxy implements Drink {
  
  private Drink drinkImpl;
  
  //通過(guò)構(gòu)造函數(shù)傳入Water對(duì)象
  public DrinkProxy(Drink drinkImpl) {
    this.drinkImpl = drinkImpl;
  }
  
  @Override
  public void drink() {
    //在執(zhí)行被代理對(duì)象的方法前做一些事情
    System.out.println("before drink");
    //執(zhí)行被代理對(duì)象的方法
    drinkImpl.drink();
    //在執(zhí)行被代理對(duì)象的方法后做一些事
    System.out.println("after drink");
  }

}

執(zhí)行結(jié)果

before drink
drink water
after drink

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

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

java.lang.reflect.Proxy類中可以動(dòng)態(tài)生成代理對(duì)象的方法

/**
   *返回實(shí)現(xiàn)了指定接口的對(duì)象,調(diào)用代理對(duì)象的方法會(huì)調(diào)用 
   *InvocationHandler的invoke方法
   *
   * @param  loader 獲取代理類所使用的類加載器
   * @param  interfaces 代理類所要實(shí)現(xiàn)的接口
   * @param  h 實(shí)現(xiàn)了InvocationHandler接口的對(duì)象
   * @return 代理對(duì)象
   */
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

InvocationHandler接口

/**
 *每個(gè)代理類都有一個(gè)關(guān)聯(lián)的InvocationHandler
 *當(dāng)代理對(duì)象執(zhí)行一個(gè)方法的時(shí)候會(huì)直接執(zhí)行invoke方法
 */
public interface InvocationHandler {

  /**
   * @param  調(diào)用該方法的代理對(duì)象
   * @param  method 代理對(duì)象所調(diào)用的方法
   * @param  args 調(diào)用的方法的參數(shù)
   * @return 調(diào)用的方法的返回值
   */
  public Object invoke(Object proxy, Method method, Object[] args)
}


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

例子

InvocationHandler接口的實(shí)現(xiàn)類

public class CommonInvocationHandler implements InvocationHandler {
  
  //被代理的對(duì)象
  private Object proxied;
  
  public CommonInvocationHandler(Object proxied) {
    this.proxied = proxied;
  }
  
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //在調(diào)用被代理對(duì)象的方法前做一些事情
    System.out.println("before doing something");
    //調(diào)用被代理對(duì)象的方法
    Object result = method.invoke(proxied, args);
    //在調(diào)用被代理對(duì)象的方法后做一些事情
    System.out.println("after doing something");;
    return result;
  }

}

Main

public class Main {

  public static void main(String[] args) {
    //被代理的對(duì)象
    Water water = new Water();
    //動(dòng)態(tài)獲取代理對(duì)象
    Drink waterProxy = 
        (Drink) Proxy.newProxyInstance(water.getClass().getClassLoader(),
            water.getClass().getInterfaces(), 
            new CommonInvocationHandler(water));
    //通過(guò)代理對(duì)象調(diào)用方法
    waterProxy.drink();
  }

}

輸出結(jié)果

before doing something
drink water
after doing something

也可以不要具體的被代理對(duì)象,但是必須有相應(yīng)的接口(沒(méi)有實(shí)現(xiàn)接口的類可以使用cglib實(shí)現(xiàn)動(dòng)態(tài)代理)才可以動(dòng)態(tài)獲取代理對(duì)象。像最近比較火的Retrofit就直接通過(guò)聲明好的接口使用動(dòng)態(tài)代理進(jìn)行網(wǎng)絡(luò)請(qǐng)求。

例子

簡(jiǎn)單的模擬一下retrofit

POST注解

//Post請(qǐng)求注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
 String value() default "";
}

Query注解

//Post請(qǐng)求注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
 String value() default "";
}

Service接口

public interface Service {
  //用POST注解聲明請(qǐng)求的方式和相對(duì)路徑
  @POST("/login")
  //@Query注解聲明請(qǐng)求的參數(shù)名
  void login(@Query("username")String username, 
      @Query("password")String password);
}

Main

public class Main {

  public static void main(String[] args) {
    // 動(dòng)態(tài)獲取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 {
            // 通過(guò)注解獲取請(qǐng)求的相對(duì)路徑
            String retativePath = ((POST) method.getAnnotations()[0]).value();
            System.out.println("relative path: " + retativePath);
            // 獲取參數(shù)的注解
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            // 通過(guò)參數(shù)的注解獲取請(qǐng)求參數(shù)
            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;
          }
        });
    // 調(diào)用代理對(duì)象的方法
    service.login("hello", "world");
  }

}

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

相關(guān)文章

  • 五種單件模式之Singleton的實(shí)現(xiàn)方法詳解

    五種單件模式之Singleton的實(shí)現(xiàn)方法詳解

    本篇文章是對(duì)Singleton的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-06-06
  • Java運(yùn)行Jar包內(nèi)存配置的操作

    Java運(yùn)行Jar包內(nèi)存配置的操作

    這篇文章主要介紹了Java運(yùn)行Jar包內(nèi)存配置的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-01-01
  • Java三目運(yùn)算符用法舉例

    Java三目運(yùn)算符用法舉例

    三目運(yùn)算符是我們經(jīng)常在代碼中使用的,這篇文章主要給大家介紹了關(guān)于Java三目運(yùn)算符用法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • Spring實(shí)戰(zhàn)之調(diào)用實(shí)例工廠方法創(chuàng)建Bean操作示例

    Spring實(shí)戰(zhàn)之調(diào)用實(shí)例工廠方法創(chuàng)建Bean操作示例

    這篇文章主要介紹了Spring實(shí)戰(zhàn)之調(diào)用實(shí)例工廠方法創(chuàng)建Bean操作,結(jié)合實(shí)例形式分析了實(shí)例工廠方法創(chuàng)建Bean相關(guān)配置、實(shí)現(xiàn)方法及操作注意事項(xiàng),需要的朋友可以參考下
    2019-11-11
  • 25個(gè)最好的免費(fèi)Eclipse插件

    25個(gè)最好的免費(fèi)Eclipse插件

    這篇文章為大家分享了25個(gè)讓Java程序員更高效的Eclipse插件,感興趣的朋友可以參考一下
    2015-12-12
  • 使用mybatis報(bào)Invalid bound statement解決分析

    使用mybatis報(bào)Invalid bound statement解決分析

    這篇文章主要為大家介紹了使用mybatis報(bào)Invalid bound statement原因解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 一文讀懂Jvm類加載機(jī)制

    一文讀懂Jvm類加載機(jī)制

    這篇文章主要介紹了一文讀懂Jvm類加載機(jī)制,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Springmvc返回html頁(yè)面問(wèn)題如何解決

    Springmvc返回html頁(yè)面問(wèn)題如何解決

    這篇文章主要介紹了Springmvc返回html頁(yè)面問(wèn)題如何解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Spring Cloud Config解決的問(wèn)題和案例

    Spring Cloud Config解決的問(wèn)題和案例

    Spring Cloud Config 是 Spring Cloud 套件中的一個(gè)工具,提供了在分布式系統(tǒng)中對(duì)外部化配置的服務(wù)器端和客戶端支持,本文介紹了Spring Cloud Config解決的問(wèn)題和案例,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2024-07-07
  • Java分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)原理與用法詳解

    Java分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)原理與用法詳解

    這篇文章主要介紹了Java分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)原理與用法,結(jié)合實(shí)例形式分析了java分支結(jié)構(gòu)、循環(huán)結(jié)構(gòu)、跳轉(zhuǎn)語(yǔ)句等相關(guān)概念、原理、使用技巧與操作注意事項(xiàng),需要的朋友可以參考下
    2020-02-02

最新評(píng)論