1. 程式人生 > >Spring框架——AOP(面向切面編程)詳解

Spring框架——AOP(面向切面編程)詳解

通過 cts ssi 沒有 object 引入 集中 method 可能

1 AOP概述

AOP(Aspect-Oriented Programming面向切面編程):是一種新的方法論,是對傳統 OOP(Object-Oriented Programming,面向對象編程)的補充。

AOP編程操作的主要對象是切面(aspect),而切面模塊化橫切關註點

●在應用AOP編程時,仍然需要定義公共功能,但可以明確的定義這個功能應用在哪裏,以什麽方式應用,並且不必修改受影響的類。這樣一來橫切關註點就被模塊化到特殊的類裏——這樣的類我們通常稱之為“切面”。

AOP的好處:

○每個事物邏輯位於一個位置,代碼不分散,便於維護和升級

○業務模塊更簡潔,只包含核心業務代碼

技術分享

2 AOP術語

2.1 橫切關註點

  從每個方法中抽取出來的同一類非核心業務。(抽離到方法中處理非核心業務)

2.2 切面(Aspect)

  封裝橫切關註點信息的類,每個關註點體現為一個通知方法。

2.3 通知(Advice)

  切面必須要完成的各個具體工作

2.4 目標(Target)

  被通知的對象

2.5 代理(Proxy)

  向目標對象應用通知之後創建的代理對象

2.6 連接點(Joinpoint)

  橫切關註點在程序代碼中的具體體現,對應程序執行的某個特定位置。例如:類某個方法調用前、調用後、方法捕獲到異常後等。

  在應用程序中可以使用橫縱兩個坐標來定位一個具體的連接點:

2.7 切入點(pointcut)

  定位連接點的方式。每個類的方法中都包含多個連接點,所以連接點是類中客觀存在的事物。如果把連接點看作數據庫中的記錄,那麽切入點就是查詢條件——AOP可以通過切入點定位到特定的連接點。

  切點通過org.springframework.aop.Pointcut 接口進行描述,它使用類和方法作為連接點的查詢條件。

3 AspectJ

3.1 簡介

AspectJJava社區裏最完整最流行的AOP框架。

Spring2.0以上版本中,可以使用基於AspectJ註解或基於XML配置的AOP

3.2 Spring中啟用AspectJ註解支持

①導入JAR

aopalliance.jar

aspectj.weaver.jar

spring-aspects.jar

②引入aop名稱空間

技術分享

③配置

<aop:aspectj-autoproxy>

Spring IOC容器偵測到bean配置文件中的<aop:aspectj-autoproxy>元素時,會自動為與AspectJ切面匹配的bean創建代理

3.3 AspectJ註解聲明切面

①要在Spring中聲明AspectJ切面,只需要在IOC容器中將切面聲明為bean實例。②當在Spring IOC容器中初始化AspectJ切面之後,Spring IOC容器就會為那些與 AspectJ切面相匹配的bean創建代理。

③在AspectJ註解中,切面只是一個帶有@Aspect註解的Java類,它往往要包含很多通知。

④通知是標註有某種註解的簡單的Java方法。

AspectJ支持5種類型的通知註解:

  [1]@Before:前置通知,在方法執行之前執行

  [2]@After:後置通知,在方法執行之後執行

  [3]@AfterRunning:返回通知,在方法返回結果之後執行

  [4]@AfterThrowing:異常通知,在方法拋出異常之後執行

  [5]@Around:環繞通知,圍繞著方法執行

4 切入點表達式

4.1 作用

通過表達式的方式定位一個或多個具體的連接點。

4.2 語法細節

①切入點表達式的語法格式

execution([權限修飾符] [返回值類型] [簡單類名/全類名] [方法名]([參數列表]))

②舉例說明

表達式

execution(* com.atguigu.spring.ArithmeticCalculator.*(..))

含義

ArithmeticCalculator接口中聲明的所有方法。

第一個“*”代表任意修飾符及任意返回值。

第二個“*”代表任意方法。

..”匹配任意數量、任意類型的參數。

若目標類、接口與該切面類在同一個包中可以省略包名。

表達式

execution(public * ArithmeticCalculator.*(..))

含義

ArithmeticCalculator接口的所有公有方法

表達式

execution(public double ArithmeticCalculator.*(..))

含義

ArithmeticCalculator接口中返回double類型數值的方法

表達式

execution(public double ArithmeticCalculator.*(double, ..))

含義

第一個參數為double類型的方法。

..” 匹配任意數量、任意類型的參數。

表達式

execution(public double ArithmeticCalculator.*(double, double))

含義

參數類型為doubledouble類型的方法

③在AspectJ中,切入點表達式可以通過 “&&”、“||”、“!”等操作符結合起來。

表達式

execution (* *.add(int,..)) || execution(* *.sub(int,..))

含義

任意類中第一個參數為int類型的add方法或sub方法

4.3 切入點表達式應用到實際的切面類中

5 當前連接點細節

5.1 概述

切入點表達式通常都會是從宏觀上定位一組方法,和具體某個通知的註解結合起來就能夠確定對應的連接點。那麽就一個具體的連接點而言,我們可能會關心這個連接點的一些具體信息,例如:當前連接點所在方法的方法名、當前傳入的參數值等等。這些信息都封裝在JoinPoint接口的實例對象中。

5.2 JoinPoint

6 通知

6.1 概述

l 在具體的連接點上要執行的操作。

l 一個切面可以包括一個或者多個通知。

l 通知所使用的註解的值往往是切入點表達式。

6.2 前置通知

l 前置通知:在方法執行之前執行的通知

l 使用@Before註解

6.3 後置通知

l 後置通知:後置通知是在連接點完成之後執行的,即連接點返回結果或者拋出異常的時候

l 使用@After註解

6.4 返回通知

l 返回通知:無論連接點是正常返回還是拋出異常,後置通知都會執行。如果只想在連接點返回的時候記錄日誌,應使用返回通知代替後置通知。

l 使用@AfterReturning註解

l 在返回通知中訪問連接點的返回值

  • 在返回通知中,只要將returning屬性添加到@AfterReturning註解中,就可以訪問連接點的返回值。該屬性的值即為用來傳入返回值的參數名稱
  • 必須在通知方法的簽名中添加一個同名參數。在運行時Spring AOP會通過這個參數傳遞返回值
  • 原始的切點表達式需要出現在pointcut屬性中

6.5 異常通知

l 異常通知:只在連接點拋出異常時才執行異常通知

l throwing屬性添加到@AfterThrowing註解中,也可以訪問連接點拋出的異常。Throwable是所有錯誤和異常類的頂級父類,所以在異常通知方法可以捕獲到任何錯誤和異常。

l 如果只對某種特殊的異常類型感興趣,可以將參數聲明為其他異常的參數類型。然後通知就只在拋出這個類型及其子類的異常時才被執行

6.6 環繞通知

l 環繞通知是所有通知類型中功能最為強大的,能夠全面地控制連接點,甚至可以控制是否執行連接點。

l 對於環繞通知來說,連接點的參數類型必須是ProceedingJoinPoint。它是 JoinPoint的子接口,允許控制何時執行,是否執行連接點。

l 在環繞通知中需要明確調用ProceedingJoinPointproceed()方法來執行被代理的方法。如果忘記這樣做就會導致通知被執行了,但目標方法沒有被執行。

l 註意:環繞通知的方法需要返回目標方法執行之後的結果,即調用 joinPoint.proceed();的返回值,否則會出現空指針異常。

6.7 重用切入點定義

l 在編寫AspectJ切面時,可以直接在通知註解中書寫切入點表達式。但同一個切點表達式可能會在多個通知中重復出現。

l AspectJ切面中,可以通過@Pointcut註解將一個切入點聲明成簡單的方法。切入點的方法體通常是空的,因為將切入點定義與應用程序邏輯混在一起是不合理的。

l 切入點方法的訪問控制符同時也控制著這個切入點的可見性。如果切入點要在多個切面中共用,最好將它們集中在一個公共的類中。在這種情況下,它們必須被聲明為public。在引入這個切入點時,必須將類名也包括在內。如果類沒有與這個切面放在同一個包中,還必須包含包名。

l 其他通知可以通過方法名稱引入該切入點

6.8 指定切面的優先級

l 在同一個連接點上應用不止一個切面時,除非明確指定,否則它們的優先級是不確定的。

l 切面的優先級可以通過實現Ordered接口或利用@Order註解指定。

l 實現Ordered接口,getOrder()方法的返回值越小,優先級越高。

l 若使用@Order註解,序號出現在註解中

6.9註意:

上面的AOP都是通過註解實現的,AOP實際上也可以通過xml配置的方式實現!

<!-- 1.將需要加載到IOC容器中的bean配置好 -->
<bean id="logAspect" class="com.neuedu.aop.proxy.LogAspect"></bean>
<bean id="txAspect" class="com.neuedu.aop.target.TxAspect"></bean>
<bean id="calculator" class="com.neuedu.aop.target.MathCalculatorImpl"></bean>

<!-- 2.配置AOP,需要導入AOP名稱空間 -->
<aop:config>
<!-- 聲明切入點表達式 -->
<aop:pointcut expression="execution(* com.neuedu.aop.target.MathCalculatorImpl.*(..))" id="myPointCut"/>
<!-- 配置日誌切面類,引用前面的類 ,通過order屬性控制優先級-->
<aop:aspect ref="logAspect" order="25">
<!-- 通過method屬性指定切面類的切面方法,通過pointcut-ref指定切入點表達式 -->
<aop:before method="showBeginLog" pointcut-ref="myPointCut"/>
<aop:after method="showAfterLog" pointcut-ref="myPointCut"/>
<aop:after-throwing method="showExceptionLog" pointcut-ref="myPointCut" throwing="ex"/>
<aop:after-returning method="showReturnLog" pointcut-ref="myPointCut" returning="result"/>
<aop:around method="around" pointcut-ref="myPointCut"/>
</aop:aspect>

<!-- 配置事務切面類,引用前面的類 -->
<aop:aspect ref="txAspect" order="20">
<aop:around method="around" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>

  

需要知道的是:事務的管理是和AOP是有很大關系的,即聲明式事務的底層是用事務實現的!

Spring框架——AOP(面向切面編程)詳解