AOP 概念

讓我們首先定義一些核心的 AOP 概念和術語。這些術語並非 Spring 特有。遺憾的是,AOP 術語並不是特別直觀。然而,如果 Spring 使用自己的術語,會更加令人困惑。

  • 切面(Aspect):對跨越多個類的關注點的模組化。事務管理就是企業 Java 應用中橫切關注點的一個很好的例子。在 Spring AOP 中,切面透過普通類(基於 Schema 的方法)或使用 @Aspect 註解標記的普通類(@AspectJ 風格)來實現。

  • 連線點(Join point):程式執行期間的某個點,例如方法的執行或異常的處理。在 Spring AOP 中,連線點總是代表方法的執行。

  • 通知(Advice):切面在特定連線點採取的行動。不同型別的通知包括“環繞通知”、“前置通知”和“後置通知”。(通知型別稍後討論。)許多 AOP 框架,包括 Spring,將通知建模為攔截器,並在連線點周圍維護一個攔截器鏈。

  • 切點(Pointcut):匹配連線點的謂詞。通知與切點表示式相關聯,並在切點匹配到的任何連線點處執行(例如,執行某個特定名稱的方法)。透過切點表示式匹配連線點的概念是 AOP 的核心,Spring 預設使用 AspectJ 的切點表示式語言。

  • 引入(Introduction):代表某個型別宣告額外的方法或欄位。Spring AOP 允許你為任何被通知的物件引入新的介面(以及相應的實現)。例如,你可以使用引入來使一個 bean 實現 IsModified 介面,從而簡化快取。(在 AspectJ 社群中,引入被稱為 inter-type declaration。)

  • 目標物件(Target object):一個被一個或多個切面通知的物件。也稱為“被通知物件”(advised object)。由於 Spring AOP 是透過執行時代理實現的,因此這個物件總是一個代理物件。

  • AOP 代理(AOP proxy):由 AOP 框架建立的物件,用於實現切面契約(通知方法執行等)。在 Spring Framework 中,AOP 代理是 JDK 動態代理或 CGLIB 代理。

  • 織入(Weaving):將切面與應用程式的其他型別或物件連線起來,以建立被通知的物件。這可以在編譯時(例如,使用 AspectJ 編譯器)、載入時或執行時完成。Spring AOP 與其他純 Java AOP 框架一樣,在執行時執行織入。

Spring AOP 包括以下通知型別:

  • 前置通知(Before advice):在連線點之前執行的通知,但它沒有能力阻止執行流進行到連線點(除非它丟擲異常)。

  • 後置返回通知(After returning advice):在連線點正常完成(例如,方法返回而沒有丟擲異常)後執行的通知。

  • 後置異常通知(After throwing advice):如果方法因丟擲異常而退出時執行的通知。

  • 後置(最終)通知(After (finally) advice):無論連線點以何種方式退出(正常返回或丟擲異常)都執行的通知。

  • 環繞通知(Around advice):圍繞連線點(例如方法呼叫)的通知。這是功能最強大的通知型別。環繞通知可以在方法呼叫之前和之後執行自定義行為。它還負責選擇是否繼續執行連線點,或者透過返回自己的返回值或丟擲異常來縮短被通知方法的執行。

環繞通知是最通用的通知型別。由於 Spring AOP 像 AspectJ 一樣提供了全範圍的通知型別,我們建議你使用能夠實現所需行為的最弱的通知型別。例如,如果你只需要用方法的返回值更新快取,那麼實現一個後置返回通知比環繞通知更好,儘管環繞通知也能實現同樣的事情。使用最具體的通知型別提供了更簡單的程式設計模型,減少了出錯的可能性。例如,在使用環繞通知時,你不需要在 JoinPoint 上呼叫 proceed() 方法,因此也不會因為忘記呼叫它而出錯。

所有通知引數都是靜態型別的,因此你可以使用適當型別的通知引數(例如,方法執行返回值的型別),而不是 Object 陣列。

透過切點匹配連線點的概念是 AOP 的關鍵,它與僅提供攔截功能的舊技術有所區別。切點使得通知可以獨立於面向物件層次結構進行目標定位。例如,你可以將提供宣告式事務管理的環繞通知應用於跨越多個物件的方法集(例如服務層中的所有業務操作)。