1. 程式人生 > >設計模式 _第六招式_代理模式(動態代理)

設計模式 _第六招式_代理模式(動態代理)

一、定義

動態代理是在實現階段不用關心代理的是誰,而在執行階段才指定代理哪個物件。面向切面程式設計(AOP)其核心就是採用的動態代理機制。

二、程式碼演示

2.1 類圖
在這裡插入圖片描述
上面類圖,是兩條獨立的發展線路。動態代理實現代理的職責,業務邏輯Subject實現先關業務邏輯,兩者沒有必然的相互耦合的關係。通知Advices從另外一個切面切入,最終高層通過Client進行耦合,完成業務的邏輯封裝。
2.2 業務邏輯抽象主題

public interface Subject {
    //業務操作
    public void  doSomething(String str);
}

2.3 業務邏輯真實主題

public class RealSubject implements Subject {

    public void  doSomething(String str){
        System.out.println("do something!---------->"+str);
    }
}

2.4 動態代理Handler類

public class MyInvocationHandler implements InvocationHandler {
    //被代理狀態
    private  Object target = null ;
    public MyInvocationHandler(Object _obj){
        this.target = _obj;
    }
    //代理方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
    //執行被代理的方法
      return  method.invoke(this.target,args);
    }
}

備註:所有通過動態代理實現的方法全部通過invoke方法呼叫。
2.5 動態代理類

public class DymamicProxy<T> {
    public static <T> T  newProxyInstance(ClassLoader loader, Class<?> []interfaces, InvocationHandler h){
        //尋找JoinPiont連線點,AOP框架使用元資料定義
       if (true){
           (new BeforeAdvice()).exec();
       }
       return (T)Proxy.newProxyInstance(loader,interfaces,h);
    }
}

2.6 通知介面及實現類

public interface IAdvice {
    //通知只有一個方法
    public void exec();
}
public class BeforeAdvice implements IAdvice {
    public void exec(){
        System.out.println("我是前置通知,我被執行了!");
    }
}

2.7 動態代理場景類

public class Client {
    public  static void main(String args[]){
        //定義個主題
        Subject   subject = new RealSubject();
        //定義一個Handler
        InvocationHandler  handler = new MyInvocationHandler(subject);
        //定義一個主題的代理
        Subject subjectProxy = DymamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler);
        //代理的行為
        subjectProxy.doSomething("Finish");
    }
}

執行結果:

我是前置通知,我被執行了!
do something!---------->Finish

三、優點

3.1 動態代理能有效的從切面實現業務邏輯, 降低與業務程式碼的耦合度。

四、缺點

五、應用場景

動態代理是一個通用的代理框架,Spirng AOP 和 AspectJ 都是用動態代理實現, 在企業應用動態代理實現許可權, 日誌,事務處理等業務邏輯。

六、注意事項

6.1 (T)Object object = (T)Proxy.newProxyInstance(c.getClassLoader(), c.getInterfaces(), new MyInvocationHandler(_obj) )
該方法是動態代理的核心由jdk維護,為什麼喲啊重新生成物件呢 ? 注意 c.getInterfaces()會查詢該類的所有介面,然後new MyInvocationHandler(_obj) 實現介面的所有方法,方法都是空,由其invoke方法接管所有方法的實現,其動態呼叫過程如圖:
在這裡插入圖片描述
6.2 動態代理必選滿足如下邏輯

  1. A、業務代理類必須要實現一個介面,因為“subject.getClass().getInterfaces()”需要取介面資訊
  2. B、必須要有一個代理處理類。如:MyInvocationHandler 該類必須實現InvocationHandler介面invoke方法
  3. C、必須生成代理物件。如:Subject subjectProxy = DymamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler); C、必須生成代理物件。如:Subject subjectProxy = DymamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler);