1. 程式人生 > >spring09----AOP基礎概念

spring09----AOP基礎概念

一. 什麼是AOP

考慮這樣一個問題:需要對系統中的某些業務做日誌記錄,比如支付系統中的支付業務需要記錄支付相關日誌,對 於支付系統可能相當複雜,比如可能有自己的支付系統,也可能引入第三方支付平臺,面對這樣的支付系統該如何解決 呢?

1. 傳統解決方案

1)日誌部分提前公共類LogUtils,定義“longPayBegin”方法用於記錄支付開始日誌,“logPayEnd”用於 記錄支付結果:

2)支付部分,定義IPayService介面並定義支付方法“pay”,並定義了兩個實現:“PointPayService”表示 積分支付,“RMBPayService”表示人民幣支付;並且在每個支付實現中支付邏輯和記錄日誌:

3)支付實現很明顯有重複程式碼,這個重複很明顯可以使用模板設計模式消除重複:

4)到此我們設計了一個可以複用的介面;但大家覺得這樣記錄日誌會很好嗎,有沒有更好的解決方案?
如果對積分支付方式新增統計功能,比如在支付時記錄下使用者總積分數、當前消費的積分數,那我們該如何做呢?直接 修改原始碼新增日誌記錄,這完全違背了面向物件最重要的原則之一:開閉原則(對擴充套件開放,對修改關閉)?

2. 更好的解決方案

在我們的支付元件中由於使用了日誌元件,即日誌模組橫切於支付元件,在傳統程式設計中很難將日誌元件分離出來,即
不耦合我們的支付元件;因此面向方面程式設計AOP就誕生了,它能分離我們的元件,使元件完全不耦合:

1)採用面向方面程式設計後,我們的支付元件看起來如下所示,程式碼中不再有日誌元件的任何東西;

2)所有日誌相關的提取到一個切面中,AOP實現者會在合適的時候將日誌功能織入到我們的支付元件中去,從而完全 解耦支付元件和日誌元件。

面向方面程式設計(AOP):也可稱為面向切面程式設計,是一種程式設計正規化,提供從另一個角度來考慮程式結構從而完善面向對 象程式設計(OOP)。

在進行OOP開發時,都是基於對元件(比如類)進行開發,然後對元件進行組合,OOP最大問題就是無法解耦組 件進行開發,比如我們上邊舉例,而AOP就是為了克服這個問題而出現的,它來進行這種耦合的分離。

AOP為開發者提供一種進行橫切關注點(比如日誌關注點橫切了支付關注點)分離並織入的機制,把橫切關注點分 離,然後通過某種技術織入到系統中,從而無耦合的完成了我們的功能。

二. AOP能幹什麼

AOP主要用於橫切關注點分離和織入,因此需要理解橫切關注點和織入:

  • 關注點:可以認為是所關注的任何東西,比如上邊的支付元件;
  • 關注點分離:將問題細化從而單獨部分,即可以理解為不可再分割的元件,如上邊的日誌元件和支付元件;
  • 橫切關注點:一個元件無法完成需要的功能,需要其他元件協作完成,如日誌元件橫切於支付元件;
  • 織入:橫切關注點分離後,需要通過某種技術將橫切關注點融合到系統中從而完成需要的功能,因此需要織入,織入可能在編譯期、載入期、執行期等進行。

1. 傳統支付流程

2. AOP

面向切面方式,先將橫切關注點分離,再將橫切關注點織入到支付系統中:

AOP能幹什麼:
• 用於橫切關注點的分離和織入橫切關注點到系統;比如上邊提到的日誌等等;
• 完善OOP;
• 降低元件和模組之間的耦合性;
• 使系統容易擴充套件;
• 而且由於關注點分離從而可以獲得元件的更好複用。

三. AOP的基本概念

在進行AOP開發前,先熟悉幾個概念:

  • 連線點(Jointpoint):表示需要在程式中插入橫切關注點的擴充套件點,連線點可能是類初始化、方法執行、方法呼叫、欄位呼叫或處理異常等等,Spring只支援方法執行連線點,在AOP中表示為“在哪裡幹”;
  • 切入點(Pointcut):選擇一組相關連線點的模式,即可以認為連線點的集合,Spring支援perl5正則表示式和AspectJ切入點模式,Spring預設使用AspectJ語法,在AOP中表示為“在哪裡乾的集合”;
  • 通知(Advice):在連線點上執行的行為,通知提供了在AOP中需要在切入點所選擇的連線點處進行擴充套件現有行為的手段;包括前置通知(before advice)、後置通知(after advice)、環繞通知(around advice),在Spring中通過代理模式實現AOP,並通過攔截器模式以環繞連線點的攔截器鏈織入通知;在AOP中表示為“幹什麼”;
  • 方面/切面(Aspect):橫切關注點的模組化,比如上邊提到的日誌元件。可以認為是通知、引入和切入點的組合;在Spring中可以使用Schema和@AspectJ方式進行組織實現;在AOP中表示為“在哪乾和幹什麼集合”;
  • 引入(inter-type declaration):也稱為內部型別宣告,為已有的類新增額外新的欄位或方法,Spring允許引入新的介面(必須對應一個實現)到所有被代理物件(目標物件), 在AOP中表示為“幹什麼(引入什麼)”;
  • 目標物件(Target Object):需要被織入橫切關注點的物件,即該物件是切入點選擇的物件,需要被通知的物件,從而也可稱為“被通知物件”;由於Spring AOP 通過代理模式實現,從而這個物件永遠是被代理物件,在AOP中表示為“對誰幹”;
  • AOP代理(AOP Proxy):AOP框架使用代理模式建立的物件,從而實現在連線點處插入通知(即應用切面),就是通過代理來對目標物件應用切面。在Spring中,AOP代理可以用JDK動態代理或CGLIB代理實現,而通過攔截器模型應用切面。
  • 織入(Weaving):織入是一個過程,是將切面應用到目標物件從而創建出AOP代理物件的過程,織入可以在編譯期、類裝載期、執行期進行。

在AOP中,通過切入點選擇目標物件的連線點,然後在目標物件的相應連線點處織入通知,而切入點和通知就是切面 (橫切關注點),而在目標物件連線點處應用切面的實現方式是通過AOP代理物件

接下來再讓我們具體看看Spring有哪些通知型別:

  • 前置通知(Before Advice):在切入點選擇的連線點處的方法之前執行的通知,該通知不影響正常程式執行流程(除非該通知丟擲異常,該異常將中斷當前方法鏈的執行而返回)。
  • 後置通知(After Advice):在切入點選擇的連線點處的方法之後執行的通知,包括如下型別的後置通知:
  1. 後置返回通知(After returning Advice):在切入點選擇的連線點處的方法正常執行完畢時執行的通知,必須是連線點處的方法沒丟擲任何異常正常返回時才呼叫後置通知。
  2. 後置異常通知(After throwing Advice): 在切入點選擇的連線點處的方法丟擲異常返回時執行的通知,必須是連線點處的方法丟擲任何異常返回時才呼叫異常通知。
  3. 後置最終通知(After finally Advice): 在切入點選擇的連線點處的方法返回時執行的通知,不管拋沒丟擲異常都執行,類似於Java中的finally塊。
  • 環繞通知(Around Advices):環繞著在切入點選擇的連線點處的方法所執行的通知,環繞通知可以在方法呼叫之前和之後自定義任何行為,並且可以決定是否執行連線點處的方法、替換返回值、丟擲異常等等。

四. AOP代理

AOP代理就是AOP框架通過代理模式建立的物件,Spring使用JDK動態代理或CGLIB代理來實現,Spring預設使用 JDK動態代理來實現,從而任何介面都可別代理,如果被代理的物件實現不是介面將預設使用CGLIB代理,不過CGLIB 代理當然也可應用到介面。

AOP代理的目的就是將切面織入到目標物件。

 

 

參考文獻:

https://jinnianshilongnian.iteye.com/blog/1418596