1. 程式人生 > >SpringAOP之通知,連線點,切點,切面

SpringAOP之通知,連線點,切點,切面

原創地址: http://blog.csdn.net/github_34889651/article/details/51321499 

1:知識背景

軟體系統可以看成是由一組關注點組成的,其中,直接的業務關注點,是直切關注點。而為直切關注點提供服務的,就是橫切關注點。

2:面向切面的基本原理

什麼是面向切面程式設計

橫切關注點:影響應用多處的功能(安全、事務、日誌)

切面:

橫切關注點被模組化為特殊的類,這些類稱為切面

優點:

每個關注點現在都集中於一處,而不是分散到多處程式碼中 
服務模組更簡潔,服務模組只需關注核心程式碼。

AOP 術語

  • 通知: 
    • 定義:切面也需要完成工作。在 AOP 術語中,切面的工作被稱為通知。
    • 工作內容:通知定義了切面是什麼以及何時使用。除了描述切面要完成的工作,通知還解決何時執行這個工作。
    • Spring 切面可應用的 5 種通知型別:
  1. Before——在方法呼叫之前呼叫通知
  2. After——在方法完成之後呼叫通知,無論方法執行成功與否
  3. After-returning——在方法執行成功之後呼叫通知
  4. After-throwing——在方法丟擲異常後進行通知
  5. Around——通知包裹了被通知的方法,在被通知的方法呼叫之前和呼叫之後執行自定義的行為
  • 連線點: 
    • 定義:連線點是一個應用執行過程中能夠插入一個切面的點。
    • 連線點可以是呼叫方法時、丟擲異常時、甚至修改欄位時、
    • 切面程式碼可以利用這些點插入到應用的正規流程中
    • 程式執行過程中能夠應用通知的所有點。
  • 切點: 
    • 定義:如果通知定義了“什麼”和“何時”。那麼切點就定義了“何處”。切點會匹配通知所要織入的一個或者多個連線點。
    • 通常使用明確的類或者方法來指定這些切點。
    • 作用:定義通知被應用的位置(在哪些連線點)
  • 切面: 
    • 定義:切面是通知和切點的集合,通知和切點共同定義了切面的全部功能——它是什麼,在何時何處完成其功能。
  • 引入: 
    • 引入允許我們向現有的類中新增方法或屬性
  • 織入: 
    • 織入是將切面應用到目標物件來建立的代理物件過程。
    • 切面在指定的連線點被織入到目標物件中,在目標物件的生命週期中有多個點可以織入
  1. 編譯期——切面在目標類編譯時期被織入,這種方式需要特殊編譯器。AspectJ的織入編譯器就是以這種方式織入切面。
  2. 類載入期——切面在類載入到
  3. JVM ,這種方式需要特殊的類載入器,他可以在目標類被引入應用之前增強該目標類的位元組碼。AspectJ5 的 LTW 就支援這種織入方式
  4. 執行期——切面在應用執行期間的某個時刻被織入。一般情況下,在織入切面時候,AOP 容器會為目標物件動態的建立代理物件。Spring AOP 就是以這種方式織入切面。

3:Spring 對 AOP 的支援

  • 並不是所有的 AOP 框架都是一樣的,他們在連線點模型上可能有強弱之分。 
    • 有些允許對欄位修飾符級別應用通知
    • 有些支援方法呼叫連線點
  • Spring 提供的 4 種各具特色的 AOP 支援
  1. 基於代理的經典 AOP;
  2. @AspectJ 註解驅動的切面;
  3. 純 POJO 切面;
  4. 注入式 AspectJ 切面; Spring
  • 在執行期間通知物件 
    • 通過在代理類中織入包裹切面,Spring 在執行期間將切面織入到 Spring 管理的 Bean 中。 
      代理類封裝了目標類,並攔截被通知的方法呼叫,再將呼叫轉發給真正的目標 Bean 
      Spring代理機制 
      當攔截到方法呼叫時,在呼叫目標 Bean 方法之前,代理會執行切面邏輯。 
      當真正應用需要被代理的 Bean 時,Spring 才建立代理物件。如果使用 ApplicationContext,在 ApplicationContext 從 BeanFactory 中載入所有 Bean 時,Spring 建立代理物件,因為 Spring 在執行時候建立代理物件,所以我們不需要特殊的編譯器來織入 Spring AOP 的切面。
  • Spring 支援方法建立連線點 
    • 因為 Spring 基於動態代理,所以 Spring 只支援方法連線點。
    • Spring 缺失對欄位連線點的支援,無法讓我們更加細粒度的通知,例如攔截物件欄位的修改
    • Spring 缺失對構造器連線點支援,我發在 Bean 建立時候進行通知。

4:使用切點選擇連線點

  • 切點用於準確定位,確定在什麼地方應用切面通知。
  • Spring 定義切點 
    • 在 Spring AOP 中,需要使用 AspectJ 的切點表示式來定義切點。
AspectJ 指示器描述
arg ()限制連線點的指定引數為指定型別的執行方法
@args ()限制連線點匹配引數由指定註解標註的執行方法
execution ()用於匹配連線點的執行方法
this ()限制連線點匹配 AOP 代理的 Bean 引用為指定型別的類
target ()限制連線點匹配特定的執行物件,這些物件對應的類要具備指定型別註解
within()限制連線點匹配指定型別
@within()限制連線點匹配指定註釋所標註的型別(當使用 Spring AOP 時,方法定義在由指定的註解所標註的類裡)
@annotation限制匹配帶有指定註釋的連線點

1. 建立自己的切點 
這裡寫圖片描述 
- execution( ) 指示器選擇 Instrument 的 play( ) 方法。 
方法表示式是以 * 號開頭,標識了我們不關心的方法返回值的型別。 
* 後我們指定了許可權定類名和方法名。 
對於方法的引數列表,使用(..)標識切點選擇任意的 play( ) 方法,無論入參是什麼。 
- 假設我們需要匹配切點僅匹配 com.Springinaction.springidol 包。可以使用 within() 
這裡寫圖片描述 
注意 && 是將 execution( ) 和 within( ) 連線起來,形成的 and 關係。同理也可以使用 || 或關係、!非關係 
- 建立 Spring 的 bean( ) 指示器 
Spring 2.5 引入一個新的 bean( ) 指示器,該指示器允許我們在切點表示式中使用 Bean ID 來標識 Bean 
bean( ) 使用 Bean ID 或 Bean 名稱作為引數來限制切點只匹配特定 Bean。 
如下,我們希望執行 Instrument 的 play( ) 方法時候應用通知,但限定 Bean 的 ID 為 eddie 
這裡寫圖片描述 
還可以使用非操作作為除了指定 ID 的 Bean 以外的其他 Bean應用通知 
這裡寫圖片描述 
在此場景下,切面會通知被編織到所有 ID 不為 eddie 的 Bean 中

5:在 XML 中宣告切面

Spring 的 AOP 配置元素簡化了基於 POJO 切面宣告

AOP 配置元素描述
aop : advisor定義 AOP 通知器
aop : after定義 AOP 後置通知(不管被通知方法是否執行成功)
aop : after-returing定義 AOP after-returing 通知
aop : after-throwing定義 AOP after-throwing 通知
aop : around定義 AOP 環繞通知
aop : aspect定義切面
aop : aspectj-autoproxy啟動 @AspectJ 註解驅動的切面
aop : before定義 AOP 前置通知
aop : config頂層的 AOP 配置元素,大多數 aop : * 元素必須包含在 元素內
aop : declare-parents為被通知的物件引入額外介面,並透明的實現
aop : pointcut定義切點