1. 程式人生 > >面向切面的 Spring —— 什麼是面向切面程式設計?

面向切面的 Spring —— 什麼是面向切面程式設計?

Q1:面向切面程式設計(AOP)解決什麼問題?
A1:橫切關注點業務邏輯相分離。

Q2:什麼是橫切關注點?
A2:在軟體開發中,散佈於應用中多處的功能

日誌應用切面的常見範例,但並不是切面適用的唯一場景。

DI 有助於應用物件之間的解耦,而 AOP 可以實現橫切關注點與它們所影響的物件之間的解耦。

這裡寫圖片描述
上圖展示了一個被劃分為模組的典型應用。每個模組的核心功能都是為特定業務領域提供服務,但是這些模組都需要類似的輔助功能,例如安全和事務管理。

如果要重用通用功能的話,最常見的面向物件技術是繼承委託

Q1:為什麼要使用切面來取代繼承和委託?
A1:如果在整個應用中都使用相的基類,繼承

往往會導致一個脆弱的物件體系;而使用委託可能需要對委託物件進行複雜的呼叫。而使用面向切面程式設計時,我們仍然在一個地方定義通用功能,但是可以通過宣告的方式定義這個功能要以何種方式在何處應用,而無需修改受影響的類。

Q2:什麼是切面?
A2:*橫切關注點被模組化為特殊的類*,這些類被稱為切面。

Q3:使用面向切面程式設計的好處?
A3:①、現在每個關注點都集中於一個地方,而不是分散到多處程式碼中;②、服務模組更簡潔,因為它們只包含主要關注點(或核心功能)的程式碼,而次要關注點的程式碼被轉移到切面中了。

Q:AOP 術語有哪些?

A:描述切面的常用術語有通知(advice)、切點(pointcut)和連線點(join point)。

&通知(Advice)

在 AOP 術語中,切面的工作被成為通知。

Spring 切面可以應用 5 種類型的通知:

  • ①、前置通知(Before):在目標方法被呼叫之前呼叫通知功能;
  • ②、後置通知(After):在目標方法完成之後通用通知,此時不會關心方法的輸出是什麼;
  • ③、返回通知(After-returning):在目標方法成功執行之後呼叫通知;
  • ④、異常通知(After-throwing):在目標方法丟擲異常後呼叫通知;
  • ⑤、環繞通知(Around):通知包裹了被通知的方法,在被通知的方法呼叫之前和呼叫之後執行自定義的行為。

&連線點(Join point)

我們的應用可能也有數以千計的時機應用通知。這些時機被稱為連線點。連線點是在應用執行過程中能夠插入切面的一個點。這個點可以是呼叫方法時丟擲異常時甚至修改一個欄位切面程式碼可以利用這些點插入到應用的正常流程之中,並新增新的行為

&切點(Pointcut)

一個切面並不需要通知應用的所有連線點。切點有助於縮小切面所通知的連線點的範圍切點的定義會匹配通知所要織入的一個或多個連線點。我們通常使用明確的方法名稱,或是利用正則表示式定義所匹配的的方法名稱來指定這些切點。

&切面(Aspect)

切面是通知和切點的結合。通知和切點共同定義了切面的全部內容——它是什麼,在何時和何處完成其功能。

&引入(Introduction)

引入允許我們向現有的類新增新方法或屬性

&織入(Weaving)

織入是把切面應用到目標物件建立新的代理物件的過程。切面在指定的連線點被織入到目標物件中。在目標物件的生命週期裡有多個點可以進行織入:

  • 編譯期:切面在目標類編譯時織入。這種方式需要特殊的編譯器。AspectJ 的織入編譯器就是以這種方法織入切面的。
  • 類載入期:切面在目標類載入到 JVM 時被織入。這種方式需要特殊的類載入器,它可以在目標類被引入應用之前增強該目標類的位元組碼。AspectJ 5 的載入時織入就是支援以這種方式織入切面。
  • 執行期:切面在應用執行的某個時刻被織入。一般情況下,在織入切面時,AOP 容器會為目標物件動態地建立一個代理物件。Spring AOP 就是以這種方式織入切面的。

現在我們已經瞭解瞭如下知識:通知包含了需要用於多個應用物件的橫切行為連線點是程式執行過程中能夠應用通知的所有點切點定義了通知被應用的具體位置(在哪些連線點)關鍵的概念是切點定義了哪些連線點會得到通知

Q:以上 AOP 的核心概念是如何在 Spring 中實現的?

AOP 框架的基本功能:建立切點來定義切面所織入的連線點。

Q1:Spring 提供了哪幾種類型的 AOP 支援?
A1:提供了以下四種類型:

  • 基於代理的經典 Spring AOP
  • 純 POJO 切面
  • @AspectJ 註解驅動的切面
  • 注入式 AspectJ 切面(適用於 Spring 各版本)

前三種都是 Spring AOP 實現的變體,Spring AOP 構建在動態代理基礎之上,因此,Spring 對 AOP 的支援侷限於方法攔截

藉助 Spring 的 aop 名稱空間,我們可以將純 POJO 轉換為切面。實際上,這些 POJO 只是提供了滿足切點條件時所要呼叫的方法。但是需要 XML 配置

Spring 借鑑了 AspectJ 的切面,以提供註解驅動的 AOP。本質上,它依然是 Spring 基於代理的 AOP,但是程式設計模型幾乎與編寫成熟的 AspectJ 註解切面完全一致。這種 AOP 風格的好處在於能夠不使用 XML 來完成功能

如果你的 AOP 需求超過了簡單的方法呼叫(如構造器屬性攔截),那麼你需要考慮使用 AspectJ 來實現切面。這種情況下,上文所示的第四種類型能夠幫助你將值注入到 AspectJ 驅動的切面中。

Q2:Spring AOP 框架有一些什麼關鍵知識?
A2:
①、Spring 通知是 Java 編寫的:我們可以使用與普通 Java 開發一樣的整合開發環境(IDE)來開發切面。而且,定義通知所應用的切點通常會使用註解或在 Spring 配置檔案裡採用 XML 來編寫。
②、Spring 在執行時通知物件:通過在代理類中包裹切面,Spring 在執行期把切面織入到 Spring 管理的 bean 中。代理類封裝了目標類,並攔截被通知方法的呼叫,再把呼叫轉發給真正的目標 bean當代理攔截到方法呼叫時,在呼叫目標 bean 方法之前,會執行切面邏輯。直到應用需要被代理的 bean 時,Spring 才建立代理物件。因為 Spring 執行時才建立代理物件,所以我們不需要特殊的編譯器來織入 Spring AOP 的切面。
③、Spring 只支援方法級別的連線點:因為 Spring 基於動態代理,所以 Spring 只支援方法連線點。然而 AspectJJBoss 還支援欄位構造器接入點。

Spring 缺少對欄位連線點的支援無法讓我們建立細粒度的通知,例如攔截物件欄位的修改
而且不支援構造器連線點,我們就無法在 bean 建立時應用通知

但是方法攔截可以滿足絕大部分的需求,如果需要方法攔截之外的連線點攔截功能,那麼我們可以利用 AspectJ 來補充 Spring AOP 的功能