SpringAOP之通知,連線點,切點,切面
原創地址: http://blog.csdn.net/github_34889651/article/details/51321499
1:知識背景
軟體系統可以看成是由一組關注點組成的,其中,直接的業務關注點,是直切關注點。而為直切關注點提供服務的,就是橫切關注點。
2:面向切面的基本原理
什麼是面向切面程式設計
橫切關注點:影響應用多處的功能(安全、事務、日誌)
切面:
橫切關注點被模組化為特殊的類,這些類稱為切面
優點:
每個關注點現在都集中於一處,而不是分散到多處程式碼中
服務模組更簡潔,服務模組只需關注核心程式碼。
AOP 術語
- 通知:
- 定義:切面也需要完成工作。在 AOP 術語中,切面的工作被稱為通知。
- 工作內容:通知定義了切面是什麼以及何時使用。除了描述切面要完成的工作,通知還解決何時執行這個工作。
- Spring 切面可應用的 5 種通知型別:
- Before——在方法呼叫之前呼叫通知
- After——在方法完成之後呼叫通知,無論方法執行成功與否
- After-returning——在方法執行成功之後呼叫通知
- After-throwing——在方法丟擲異常後進行通知
- Around——通知包裹了被通知的方法,在被通知的方法呼叫之前和呼叫之後執行自定義的行為
- 連線點:
- 定義:連線點是一個應用執行過程中能夠插入一個切面的點。
- 連線點可以是呼叫方法時、丟擲異常時、甚至修改欄位時、
- 切面程式碼可以利用這些點插入到應用的正規流程中
- 程式執行過程中能夠應用通知的所有點。
- 切點:
- 定義:如果通知定義了“什麼”和“何時”。那麼切點就定義了“何處”。切點會匹配通知所要織入的一個或者多個連線點。
- 通常使用明確的類或者方法來指定這些切點。
- 作用:定義通知被應用的位置(在哪些連線點)
- 切面:
- 定義:切面是通知和切點的集合,通知和切點共同定義了切面的全部功能——它是什麼,在何時何處完成其功能。
- 引入:
- 引入允許我們向現有的類中新增方法或屬性
- 織入:
- 織入是將切面應用到目標物件來建立的代理物件過程。
- 切面在指定的連線點被織入到目標物件中,在目標物件的生命週期中有多個點可以織入
- 編譯期——切面在目標類編譯時期被織入,這種方式需要特殊編譯器。AspectJ的織入編譯器就是以這種方式織入切面。
- 類載入期——切面在類載入到
- JVM ,這種方式需要特殊的類載入器,他可以在目標類被引入應用之前增強該目標類的位元組碼。AspectJ5 的 LTW 就支援這種織入方式
- 執行期——切面在應用執行期間的某個時刻被織入。一般情況下,在織入切面時候,AOP 容器會為目標物件動態的建立代理物件。Spring AOP 就是以這種方式織入切面。
3:Spring 對 AOP 的支援
- 並不是所有的 AOP 框架都是一樣的,他們在連線點模型上可能有強弱之分。
- 有些允許對欄位修飾符級別應用通知
- 有些支援方法呼叫連線點
- Spring 提供的 4 種各具特色的 AOP 支援
- 基於代理的經典 AOP;
- @AspectJ 註解驅動的切面;
- 純 POJO 切面;
- 注入式 AspectJ 切面; Spring
- 在執行期間通知物件
- 通過在代理類中織入包裹切面,Spring 在執行期間將切面織入到 Spring 管理的 Bean 中。
代理類封裝了目標類,並攔截被通知的方法呼叫,再將呼叫轉發給真正的目標 Bean
當攔截到方法呼叫時,在呼叫目標 Bean 方法之前,代理會執行切面邏輯。
當真正應用需要被代理的 Bean 時,Spring 才建立代理物件。如果使用 ApplicationContext,在 ApplicationContext 從 BeanFactory 中載入所有 Bean 時,Spring 建立代理物件,因為 Spring 在執行時候建立代理物件,所以我們不需要特殊的編譯器來織入 Spring AOP 的切面。
- 通過在代理類中織入包裹切面,Spring 在執行期間將切面織入到 Spring 管理的 Bean 中。
- 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 | 定義切點 |