設計模式 _第六招式_代理模式(動態代理)
阿新 • • 發佈:2018-11-07
一、定義
動態代理是在實現階段不用關心代理的是誰,而在執行階段才指定代理哪個物件。面向切面程式設計(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 動態代理必選滿足如下邏輯
- A、業務代理類必須要實現一個介面,因為“subject.getClass().getInterfaces()”需要取介面資訊
- B、必須要有一個代理處理類。如:MyInvocationHandler 該類必須實現InvocationHandler介面invoke方法
- C、必須生成代理物件。如:Subject subjectProxy = DymamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler); C、必須生成代理物件。如:Subject subjectProxy = DymamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler);