面向橫切面程式設計(Aspect Oriented Programming)。

孤芳不自賞發表於2017-08-09

什麼是動態代理?

動態代理就是在實現階段不用關心代理誰,而在執行階段才指定代理哪個物件。具體說明動態代理是根據被代理的介面生成所有的方法,也就是說給定一個介面,動態代理會宣稱“我已經實現該介面的所有方法了”。

面向切面變成(AOP),其核心就是採用了動態代理機制。AOP程式設計沒有使用什麼新的技術,但是它對我們的設計、編碼有非常大的影響,對於日誌、事務、許可權等都可以在系統設計階段不用考慮,而在設計後通過AOP的方式切過去。

代理思路:

動態代理實現代理的職責,業務邏輯Subject實現相關的邏輯功能,兩者之間沒有必然的相互耦合的關係。通知Advice從另一個切面切入,最終在高層模組也就是Client進行耦合,完成邏輯的封裝任務。

抽象主題

public interface Subject {

// 業務操作

public void doSomething(String str);

}

其中的doSomething是一種標識方法,可以有多個邏輯處理方法。

真實主題

public class RealSubject implements Subject {

// 業務操作

public void doSomething(String str) {

System.out.println("do something!--->" + str);

}

}

動態代理的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);

}

}

動態代理類

public class DynamicProxy<T> {

public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandle h) {

// 尋找JoinPoint連線點,AOP框架使用後設資料定義

if(true) {

// 執行一個前置通知

(new BeforeAdvice()).exec();

}

// 執行目標,並返回結果

return (T)Proxy.newProxyInstance(loader, interface , h);

}

}

該方法時重新生成了一個物件,為什麼要重新生成?你要使用代理,注意c.getInterfaces()這句話,這是非常有意思的一句話,是說查詢到該類的所有介面,然後實現介面的所有方法。當然了,方法都是空的,由誰具體負責接管呢?是new MyInvocationHandler(_Obj)這個物件。於是 我們知道一個類的動態代理類時這樣的一個類,由InvocationHandler的實現類實現所有的方法,由其invoke方法接管所有方法的實現。

通知介面及實現

public interface IAdvice {

// 通知只有一個方法,執行即可

}

public class BeforeAdvice implements IAdivce {

public void exec() {

System.out.println("我是前置通知,我被執行了!");

}

}

具體業務的動態代理

public class SubjectDynamicProxy extends DynamicProxy {

public static <T> newProxyInstance(Subject subject) {

// 獲得ClassLoader

ClassLoader loader = subject.getClass().getClassLoader();

// 獲得介面陣列

Class<?> classes = subject.getClass().getInterfaces();

// 獲得handler

InvocationHandler handler = new MyInvocationHandler(subject);

return newProxyInstance(loader, classes , handler);

}

}

場景類

public class Client {

public static void main(Stirng[] args) {

// 定義一個主題

Subject subject = new RealSubject();

// 定義主題的代理

Subject proxy = SubjectDynamicProxy.newProxyInstance(subject);

// 代理的行為

proxy.doSomething("Finish");

}

}

動態代理的主要意圖就是解決我們常說的“審計”問題,也就是橫切面程式設計,在不改變我們已有的程式碼結構的情況下增強或控制物件的行為。

注意:要實現動態代理的首要條件是:被代理類必須實現一個介面,回想一下前面的分析吧,當然了,現在也有很多技術如CGLIB可以實現不需要介面也可以實現動態代理的方式。

相關文章