2、代理模式

一、代理模式基本概念

定義
1、模式說(shuō)明
代理模式結(jié)構(gòu)

proxy代理對(duì)象:(1)實(shí)現(xiàn)與具體的目標(biāo)對(duì)象一樣的接口,這樣就可以使用代理來(lái)代替具體的目標(biāo)對(duì)象(2)保存一個(gè)指向具體目標(biāo)對(duì)象的引用,可以在需要的時(shí)候調(diào)用具體的目標(biāo)對(duì)象,可以控制對(duì)具體目標(biāo)對(duì)象的訪問(wèn),并可能負(fù)責(zé)創(chuàng)建和刪除它
Subject目標(biāo)接口:定義代理和具體目標(biāo)對(duì)象的接口,這樣就可以在任何使用具體目標(biāo)對(duì)象的地方使用代理對(duì)象
RealSubject具體的目標(biāo)對(duì)象:真正實(shí)現(xiàn)目標(biāo)接口要求的功能。

2、代理運(yùn)行過(guò)程
3、代理功能
  • 代理模式是通過(guò)創(chuàng)建一個(gè)代理對(duì)象,用這個(gè)代理對(duì)象去代表真實(shí)的對(duì)象,客戶端得到這個(gè)代理對(duì)象過(guò)后,對(duì)客戶端沒(méi)有什么影響,就跟得到了真實(shí)對(duì)象一樣來(lái)使用。
  • 當(dāng)客戶端操作這個(gè)代理對(duì)象的時(shí)候,實(shí)際上功能最終還是會(huì)由真實(shí)的對(duì)象來(lái)完成,只不過(guò)是通過(guò)代理操作的,也就是客戶端操作代理,代理操作真正的對(duì)象。

代理其實(shí)就是中轉(zhuǎn)的意思,用代理對(duì)象去完成真實(shí)對(duì)象的動(dòng)作。但是因?yàn)槭侵修D(zhuǎn),可以利用代理完成很多對(duì)客戶端透明的東西,比如權(quán)限驗(yàn)證等。因此代理的作用可以歸納為:把一些共有的邏輯抽象到代理類中,由代理來(lái)完成,可以大大簡(jiǎn)化代碼的。

4、代理分類
  • 靜態(tài)代理:(虛代理、保護(hù)代理、遠(yuǎn)程代理和智能指引等等)
  • 動(dòng)態(tài)代理:jdk動(dòng)態(tài)代理、cglib動(dòng)態(tài)代理

二、靜態(tài)代理示例

1、創(chuàng)建需要代理的接口對(duì)象及其實(shí)現(xiàn)類
public interface Target {
 String execute();
}
public class TargetImpl implements Target {
 public String execute() {
     System.err.println("TargetImpl execute!");
     return "targetImpl";
 }
}
2、創(chuàng)建代理對(duì)象
public class StaticProxy implements Target {
 /**
  * 需要被代理的目標(biāo)接口
  */
 private  Target target;

 public StaticProxy(Target target) {
     this.target = target;
 }

 public String execute() {
     //代理類進(jìn)行代理方法操作(相當(dāng)于中轉(zhuǎn),但是同時(shí)可以添加很多的東西,比如日志、權(quán)限等等)
     System.err.println("perProcess");
     String result = this.target.execute();
     System.out.println("postProcess");
     return result;
 }
}
3、測(cè)試
public class StaticProxyTest {
 public static void main(String[] args) {
     Target target=new TargetImpl();
     StaticProxy proxy=new StaticProxy(target);
     //代理類進(jìn)行代理處理
     String execute = proxy.execute();
     System.err.println(execute);
 }
}

結(jié)果:

postProcess
perProcess
TargetImpl execute!
targetImpl

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

靜態(tài)代理具有一個(gè)明顯的缺點(diǎn)就是如果Subject接口發(fā)生變化,那么代理類和具體的目標(biāo)實(shí)現(xiàn)都要變化,不是很靈活。而動(dòng)態(tài)代理如其名,能動(dòng)態(tài)的適應(yīng)變化,應(yīng)用更加廣泛。

1、jdk動(dòng)態(tài)代理
  • Java對(duì)代理模式提供了內(nèi)建的支持,在java.lang.reflect包下面,提供了一個(gè)Proxy的類和一個(gè)InvocationHandler的接口。
  • Java的動(dòng)態(tài)代理目前只能代理接口,基本的實(shí)現(xiàn)是依靠Java的反射機(jī)制和動(dòng)態(tài)生成class的技術(shù),來(lái)動(dòng)態(tài)生成被代理的接口的實(shí)現(xiàn)對(duì)象。
  • 使用jdk動(dòng)態(tài)代理的步驟:

(1)通過(guò)實(shí)現(xiàn)InvocationHandler接口來(lái)自定義自己的InvocationHandler;
(2)通過(guò)Proxy.getProxyClass獲得動(dòng)態(tài)代理類
(3)通過(guò)代理對(duì)象調(diào)用目標(biāo)方法

public class JdkProxyInvocation implements InvocationHandler {

 private Object target;

 public JdkProxyInvocation(Object target) {
     this.target = target;
 }

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     System.out.println("========before==========");
     Object result = method.invoke(target,args);
     System.out.println("========after===========");
     return result;
 }
}
public class JdkProxy<T> {
  /**
   * 要被代理的對(duì)象
   */
  private Class<T> target;
  /**
   * 具體處理邏輯的invoke
   */
  private InvocationHandler invocationHandler;

  public JdkProxy(Class<T> target, InvocationHandler invocationHandler) {
      this.target = target;
      this.invocationHandler = invocationHandler;

  }

  public T getProxyObject() {
      return (T) Proxy.newProxyInstance(target.getClassLoader(), 
target.getInterfaces() , invocationHandler);
  }
}
public class JdkProxyTest {
  public static void main(String[] args) {
      Target target = new TargetImpl();
      JdkProxyInvocation jdkProxyInvocation = new JdkProxyInvocation(target);
      //獲取代理對(duì)象
      Target proxy = (Target) new JdkProxy(target.getClass(), jdkProxyInvocation)
              .getProxyObject();
      proxy.execute();
  }
}

如果想深入可以看這篇分析源碼的博客:深度剖析 JDK 動(dòng)態(tài)代理機(jī)制

2、cglib代理

CGLib采用了非常底層的字節(jié)碼技術(shù),其原理是通過(guò)字節(jié)碼技術(shù)為一個(gè)類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù)攔截所有父類方法的調(diào)用,順勢(shì)織入橫切邏輯。

public class CglibProxy implements MethodInterceptor {
  //單例模式
  private static CglibProxy instance = new CglibProxy();
  public static CglibProxy getInstance(){
      return instance;
  }

  /**
   * 創(chuàng)建代理對(duì)象
   * @param cls 要代理的類
   * @param <T>
   * @return
   */
  public <T> T getProxy(Class<T> cls){
      return (T) Enhancer.create(cls, this);
  }

  public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
      System.out.println(">>>>MethodInterceptor start...");
      Object result = methodProxy.invokeSuper(obj,args);
      System.out.println(">>>>MethodInterceptor ending...");
      return result;
  }
}
public class CglibTarget {
  public String execute() {
      String message = "-----------test------------";
      System.out.println(message);
      return message;
  }
}
public class CglibTest {
  public static void main(String[] args) {
      CglibTarget proxy = CglibProxy.getInstance().getProxy(CglibTarget.class);
      proxy.execute();
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容