Spring AOP面向切面程式設計
一、AOP面向切面程式設計基本概念
在軟體系統中,有些行為對於絕大多數業務模組都是通用,例如日誌管理、許可權管理、事物管理等,在不同的業務模組中,我們很有可能會編寫相同的程式碼來完成一個共同的功能點,這就造成了極大的程式碼冗餘,和較高的維護成本,同時業務程式碼與特殊功能程式碼耦合交融到了一起,不利於系統的構建與開發。
AOP:Aspect Oriented Programming ,面向切面程式設計,就是將眾多的業務模組進行橫向切割,提煉抽取其中的相同功能程式碼進行單獨程式設計,已達到業務程式碼與非業務功能程式碼的隔離,從而使得業務邏輯部分之間的耦合度降低,提高程式的可重用性,同時提高開發效率。
AOP最重要的功能:高內聚,低耦合
二、Spring AOP的基本概念
AOP把軟體系統分成兩個部分:核心關注點和橫切關注點,業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點,描述橫切關注點的具體內容稱之為切面。
描述切面的常用概念是:通知(Advice)、切點(Pointcut)、連線點(JoinPoint)、目標物件(Target)、織入(Weaving)、代理(Proxy)、切面(aspect)
- 通知:定義了切面執行的程式碼內容是什麼,在什麼時候執行。
- 切點:一個或多個連線點的集合,通常使用具體的類名和方法名來指定這些切點,或是使用正則表示式來定義匹配的類和方法來指定這些切點。
- 連線點:在應用執行過程中能夠插入切面的一個點,這個點可以是呼叫方法時、丟擲異常時、修改一個欄位時,切面程式碼可以利用連線點插入到應用的正常流程之中,並執行切面程式碼。
- 目標物件:被代理物件。
- 織入:將通知應用到切入點的過程。
- 代理:將通知織入到目標物件之後,形成代理物件。
- 切面:切面是通知和切點的結合,通知和切點共同定義了關於切面的全部內容,切面內容是什麼,在什麼時候執行,在什麼地方執行。(切點+通知)。
Spring中實現AOP原理:
-
動態代理:被代理物件必須實現接口才能實現代理物件,如果沒有介面將不能使用動態代理技術。
-
cglib代理:第三方的代理技術,可以對任何類生成代理,代理的原理是對目標物件進行繼承代理,如果目標被物件final修飾,那麼該類無法被cglib代理。
-
如果有介面優先使用動態代理。
Spring AOP中定義了五種型別的通知:
通知型別 | 描述 |
Before | 再切點方法執行之前,呼叫通知中指定的方法。 |
After | 再切點方法執行完成之後,呼叫通知中指定的方法,不管切點方法執行是否成功。 |
After-returning | 再切點方法成功執行之後,呼叫通知中指定的方法。 |
After-throwing | 再切點方法執行丟擲異常後,呼叫通知中指定的方法。 |
Around | 通知方法包裹切點方法執行,改變切點方法中的執行邏輯 |
三、Spring AOP程式設計
1. 通過標籤方式進行切面程式設計
<!--切面配置標籤塊-->
<aop:config>
<!--切點定義,使用正則表示式來匹配連線點集合,通過id來命令切點-->
<aop:pointcut expression="execution(* com.yingcai.service.*.*(..))" id="pointcut"/>
<!--通知配置標籤塊,ref屬性定義通知執行Bean-->
<aop:aspect ref="adviceInfo">
<aop:before method="beforeAdvice" pointcut-ref="pointcut"/>
<aop:after method="afterAdvice" pointcut-ref="pointcut"/>
<aop:after-throwing method="afterThrowingAdvice" pointcut-ref="pointcut"/>
<aop:after-returning method="afterReturnAdvice" pointcut-ref="pointcut"/>
<aop:around method="aroundAdvice" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
環繞通知詳解:
通過ProceedingJoinPoin類來獲取操作連線點切入方法的相關資訊
獲取切入方法執行類名稱:
Class executeClass = proceedingJoinPoint.getTarget().getClass();
String className = executeClass.getName();
獲取切入方法名稱:
String methodName = proceedingJoinPoint.getSignature().getName();
獲取切入方法入參:
Object[] args = proceedingJoinPoint.getArgs();
執行切入方法內容:
proceedingJoinPoint.proceed();
注:環繞通知的方法格式必須與連線點方法格式相同,連線點方法有返參,環繞通知方法也必須有返參。
2. 使用註解方式進行切面程式設計
切面註解的開啟:
<aop:aspectj-autoproxy/>
-
@Aspect:標註於類上,將一個類定義為切面類。
-
@Pointcut:標註於一個普通方法上,定義切點內容。
-
@Before:標註於前置通知方法之上。
-
@After:標註於後置方法之上。
-
@AfterThrowing:標註於後置失敗通知方法之上。
-
@AfterReturning:標註於後置成功通知方法之上。
-
@Around:標註於環繞通知方法之上。