一、AOP術語
- 通知(Advice)
切面的工作被稱為通知。通知定義了切面是什么以及何時使用。除了描述切面要完成的工作,通知還解決了何時執行這個工作的問題。
5種通知類型:
前置通知(Before):在目標方法被調用之前調用通知功能
后置通知(After):在目標方法完成之后調用通知,此時不會關心方法的輸出是什么
返回通知(After-returning):在目標方法成功執行之后調用通知
異常通知(After-throwing):在目標方法拋出異常后調用通知
環繞通知(Around):通知包裹了被通知的方法,在被通知的方
法調用之前和之后執行自定義的行為
后置通知和返回通知的區別是,后置通知是不管方法是否有異常,都會執行該通知;而返回通知是方法正常結束時才會執行。
- 連接點(Join point)
連接點是在應用執行過程中能夠插入切面的一個點。 - 切點(Pointcut)
一個切面並不需要通知應用的所有連接點,切點有助於縮小切面所通知的連接點范圍。如果說通知定義了切面的“什么”和“何時”的話,那么切點就定義了“何處”。因此,切點其實就是定義了需要執行在哪些連接點上執行通知。 - 切面(Aspect)
切面是通知和切點的結合。通知和切點共同定義了切面的全部內容——它是什么,在何時和在何處完成其功能。 - 引入(Introduction)
引入允許我們向現有的類添加新方法或屬性。 - 織入(Weaving)
織入是把切面應用到目標對象並創建新的代理對象的過程。切面在指定的連接點被織入到目標對象中。在目標對象的生命周期中有很多個點可以進行織入:
編譯期:切面在目標類編譯時被織入。這種方式需要特殊的編譯器。AspectJ的織入編譯器就是以這種方式織入切面的。
類加載期:切面在目標類加載到JVM時被織入。這種方式需要特殊的類加載器,它可以在目標類被引入應用之前增強該目標類的字節碼。AspectJ 5的加載時織入就支持這種方式織入切面。
運行期:切面在應用運行的某個時刻被織入。一般情況下,在織入切面時,AOP容器會為目標對象動態的創建一個代理對象。Spring AOP就是以這種方式織入切面的。
二、Spring對AOP的支持
創建切點來定義切面所織入的連接點是AOP框架的基本功能。Spring提供了4種類型的AOP支持:
- 基於代理的經典Spring AOP;
- 純POJO切面
- @AspectJ注解驅動的切面
- 注入式AspectJ切面(適用於Spring各版本)
前三種都是Spring AOP實現的變體,Spring AOP構建在動態代理基礎之上,因此,Spring對AOP的支持局限於方法攔截。
1.Spring在運行時通知對象
通過在代理類中包裹切面,Spring在運行期把切面織入到Spring管理的bean中。如下圖所示,代理類封裝了目標類,並攔截被通知方法的調用,再把調用轉發給真正的目標bean。當代理攔截到方法調用時,在調用目標bean方法之前,會執行切面邏輯。
直到應用需要被代理的bean時,Spring才創建代理對象。如果使用的是ApplicationContext的話,在Applicationcontext從Beanfactory中加載所有bean的時候,Spring才會創建被代理的對象。因為Spring運行時才創建代理對象,所以我們不需要特殊的編譯器來織入Spring AOP的切面。
2.Spring只支持方法級別的連接點
因為Spring基於動態代理,所以Spring只支持方法連接點。這與一些其他的AOP框架是不用的,例如AspectJ和JBoss,除了方法切點,它們還提供了字段和構造器接入點。
三、通過切點來選擇連接點
以下是Spring AOP所支持的AspectJ切點指示器
AspectJ指示器 | 描述 |
---|---|
arg() | 限制連接點匹配參數為指定類型的執行方法 |
@args() | 限制連接點匹配參數由指定注解標注的執行方法 |
execution() | 用於匹配是連接點的執行方法 |
this() | 限制連接點匹配AOP代理的bean引用為指定類型的類 |
target | 限制連接點匹配目標對象為指定類型的類 |
@target | 限制連接點匹配特定的執行對象,這些對象對應的類要具有指定類型的注解 |
within() | 限制連接點匹配指定的類型 |
@within() | 限制連接點匹配指定注解所標注的類型(當使用Spring AOP時,方法定義在由指定的注解所標注的類里) |
@annotation | 限定匹配帶有指定注解的連接點 |
- 編寫切點
2.定義切面