【Spring實戰學習筆記】第4章 面向切面的Spring

目錄

4.1 什麼是面向切面編程

4.2 通過切點來選擇連接點

4.3 使用註解創建切面

4.4 在XML中聲明切面

4.5 注入AspectJ切面

4.6 小結


在軟件開發中,散佈於應用中多處的功能被稱爲橫切關注點(cross cutting concern)。通常來講,這些橫切關注點從概念上是與應用的業務邏輯相分離的(但是往往會直接嵌入到應用的業務邏輯之中)。把這些橫切關注點與業務邏輯相分離正是面向切面編程(AOP)所要解決的問題。

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

4.1 什麼是面向切面編程

 

每個模塊的核心功能都是爲特定業務領域提供服務,但是這些模塊都需要類似的輔助功能,例如安全和事務管理。

在使用面向切面編程時,我們仍然在一個地方定義通用功能,但是可以通過聲明的方式定義這個功能要以何種方式在何處應用,而無需修改受影響的類。橫切關注點可以被模塊化爲特殊的類,這些類被稱爲切面(aspect)。這樣做有兩個好處:首先,現在每個關注點都集中於一個地方,而不是分散到多處代碼中;其次,服務模塊更簡潔,因爲它們只包含主要關注點(或核心功能)的代碼,而次要關注點的代碼被轉移到切面中了

4.1.1 AOP 術語

描述切面的常用術語有通知(advice)、切點(point cut)和連接點(join point)

 

通知(Advice):

通知定義了切面是什麼以及何時使用。除了描述切面要完成的工作,通知還解決了何時執行這個工作的問題。它應該應用在某個方法被調用之前?之後?之前和之後都調用?還是隻在方法拋出異常時調用?

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

  • 前置通知(Before):在目標方法被調用之前調用通知功能;
  • 後置通知(After):在目標方法完成之後調用通知,此時不會關心方法的輸出是什麼;
  • 返回通知(After returning):在目標方法成功執行之後調用通知;
  • 異常通知(After throwing):在目標方法拋出異常後調用通知;
  • 環繞通知(Around):通知包裹了被通知的方法,在被通知的方法調用之前和調用之後執行自定義的行爲。

連接點(Joint Point):

我們的應用可能也有數以千計的時機應用通知。這些時機被稱爲連接點。連接點是在應用執行過程中能夠插入切面的一個點。這個點可以是調用方法時、拋出異常時、甚至修改一個字段時。切面代碼可以利用這些點插入到應用的正常流程之中,並添加新的行爲

切點(Point Cut):

如果說通知定義了切面的“什麼”和“何時”的話,那麼切點就定義了“何處”。切點的定義會匹配通知所要織入的一個或多個連接點。我們通常使用明確的類和方法名稱,或是利用正則表達式定義所匹配的類和方法名稱來指定這些切點

切面(Aspect):

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

引入(Introduction)

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

織入(Weaving):

織入是把切面應用到目標對象並創建新的代理對象的過程。切面在指定的連接點被織入到目標對象中。在目標對象的生命週期裏有多個點可以進行織入:編譯期、類加載期、運行期

總結:

通知包含了需要用於多個應用對象的橫切行爲;

連接點是程序執行過程中能夠應用通知的所有點;

切點定義了通知被應用的具體位置(在哪些連接點)

4.1.2 Spring 對 AOP 的支持

SpringAOP構建在動態代理基礎之上,因此,Spring對AOP的支持侷限於方法攔截。

Spring所創建的通知都是用標準的Java類編寫的,定義通知所應用的切點通常會使用註解或在Spring配置文件裏採用XML來編寫。

通過在代理類中包裹切面,Spring在運行期把切面織入到Spring管理的bean中。代理類封裝了目標類,並攔截被通知方法的調用,再把調用轉發給真正的目標bean。當代理攔截到方法調用時,在調用目標bean方法之前,會執行切面邏輯。

 

因爲Spring基於動態代理,所以Spring只支持方法連接點。

4.2 通過切點來選擇連接點

只有execution指示器是實際執行匹配的,其他的指示器都是用來限制匹配的。這說明execution指示器是我們在編寫切點定義時最主要使用的指示器。

4.2.1 編寫切點

使用AspectJ切點表達式來選擇Performance的perform()方法:

 

方法表達式以“*”號開始,表明了我們不關心方法返回值的類型。我們指定了全限定類名和方法名。

對於方法參數列表,我們使用兩個點號(..)表明切點要選擇任意的方法

使用限定方法:

4.2.2 在切點中選擇 bean

Spring還引入了一個新的bean()指示器,它允許我們在切點表達式中使用bean的ID來標識bean。bean()使用beanID或bean名稱作爲參數來限制切點只匹配特定的bean。

示例:

execution(*concert.Performance.perform()) and bean('woodstock')

execution(*concert.Performance.perform()) and !bean('woodstock')

4.3 使用註解創建切面

4.3.1 定義切面

Audience類使用@AspectJ註解進行了標註。該註解表明Audience不僅僅是一個POJO,還是一個切面。Audience類中的方法都使用註解來定義切面的具體行爲。

 

AspectJ提供了五個註解來定義通知:

 

@Pointcut註解能夠在一個@AspectJ切面內定義可重用的切點。

如果你使用JavaConfig的話,可以在配置類的類級別上通過使用EnableAspectJAutoProxy註解啓用自動代理功能

 

在Spring中要使用XML來裝配bean的話,那麼需要使用Springaop命名空間中的<aop:aspectj-autoproxy>元素

 

Spring的AspectJ自動代理僅僅使用@AspectJ作爲創建切面的指導,切面依然是基於代理的。在本質上,它依然是Spring基於代理的切面。這一點非常重要,因爲這意味着儘管使用的是@AspectJ註解,但我們仍然限於代理方法的調用。

4.3.2 創建環繞通知

 

環繞通知將ProceedingJoinPoint作爲參數。通知方法中可以做任何的事情,當要將控制權交給被通知的方法時,它需要調用ProceedingJoinPoint的proceed()方法。

 

你可以不調用proceed()方法,從而阻塞對被通知方法的訪問,與之類似,你也可以在通知中對它進行多次調用。要這樣做的一個場景就是實現重試邏輯,也就是在被通知方法失敗後,進行重複嘗試。

4.3.3 處理通知中的參數

 

切點表達式中的args(trackNumber)限定符。它表明傳遞給playTrack()方法的int類型參數也會傳遞到通知中去。參數的名稱trackNumber也與切點方法簽名中的參數相匹配。

 

4.3.4 利用註解引入新功能

利用被稱爲引入的AOP概念,切面可以爲Springbean添加新方法。

當Spring發現一個bean使用了@Aspect註解時,Spring就會創建一個代理,然後將調用委託給被代理的bean或被引入的實現,這取決於調用的方法屬於被代理的bean還是屬於被引入的接口。

4.4 在XML中聲明切面

如果你沒有源碼的話,或者不想將AspectJ註解放到你的代碼之中,Spring爲切面提供了另外一種可選方案 —— 在SpringXML配置文件中聲明切面。在Spring的aop命名空間中,提供了多個元素用來在XML中聲明切面

 

 

4.4.1 聲明前置通知和後置通知

通過XML將無註解的Audience聲明爲切面

 

4.4.2 聲明環繞通知

在XML中使用<aop:around>元素聲明環繞通知

 

4.5 注入AspectJ切面

雖然SpringAOP能夠滿足許多應用的切面需求,但是與AspectJ相比,SpringAOP是一個功能比較弱的AOP解決方案。AspectJ提供了SpringAOP所不能支持的許多類型的切點。

——不做詳細記錄

4.6 小結

在 Spring 中使用切面,需要:

  • 定義切面:定義切面類、方法和配置,用來指明切面要做什麼、具體在哪裏執行,以及在什麼時候執行(Java 配置 或者 XML 配置)
  • 啓用切面:通過 Java 配置,或者 XML 配置來啓用切面

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章