SpringAOP中的通知Advice詳解
一、概述
AOP 中的通知是基于連接點(Join point)業(yè)務邏輯的一種增強,Spring AOP 提供了下面五種通知類型:
- Before advice(前置通知):連接點前面執(zhí)行,不能終止后續(xù)流程,除非拋異常
- After returning advice(后置通知):連接點正常返回時執(zhí)行,有異常不執(zhí)行
- Around advice(環(huán)繞通知):圍繞連接點前后執(zhí)行,也能捕獲異常處理
- After advice(最終通知):連接點退出時執(zhí)行,無論是正常退出還是異常退出
- After throwing advice(異常通知):連接點方法拋出異常時執(zhí)行
AOP 的連接點一般是指目標類的方法,五種通知類型執(zhí)行的節(jié)點如下:

二、通知的定義
Spring AOP 可以基于 XML 方式和基于注解方式定義,只是寫法不同,這里只使用注解的方式來講解通知的詳細用法。
1. 前置通知
在 @Aspect 切面類中使用 @Before 注解簡單地定義一個前置通知。
@Aspect
@Component
public class DemoAspect {
@Before("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public void doBefore() {
// 自定義邏輯
}
}2. 后置通知
方法正常返回,會執(zhí)行后置通知,使用 @AfterReturning 注解定義后置通知。
@AfterReturning("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public void doAfterReturning() {
// 自定義邏輯
}注解的 returning 屬性可以綁定目標方法返回值,用于在通知中獲取目標方法執(zhí)行完成后的返回結果。
@AfterReturning(pointcut = "pointcut()", returning = "retVal")
public void doAfterReturning(Object retVal) {
// 自定義邏輯(通過參數(shù)綁定方法切入點方法的返回值)
}當注解使用了 returning 屬性時,切入點會增加返回值類型的限制,上面使用的 Object 類型可以匹配到所有返回值類型的目標方法。
例如下面的情況,后置通知的代碼不會被執(zhí)行:
// 目標方法
public String doService() {
return "碼匠公眾號";
}
// 后置通知定義
@AfterReturning(pointcut = "pointcut()", returning = "retVal")
public void doAfterReturning(Integer retVal) {
// 目標方法返回值是String類型,結果參數(shù)綁定類型是Integer,該通知不會被執(zhí)行
}3. 環(huán)繞通知
環(huán)繞通知可以在方法執(zhí)行的任何節(jié)點添加邏輯,它可以實現(xiàn)另外 4 種通知的功能。
如果需要以線程安全的方式在方法執(zhí)行前后共享狀態(tài),可以使用環(huán)繞通知。
用 @Around 注解來定義環(huán)繞通知,需要使用 ProceedingJoinPoint 作為參數(shù),來執(zhí)行目標方法調(diào)用。
@Around("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 方法執(zhí)行前邏輯
Object retVal = joinPoint.proceed();
// 方法執(zhí)行后邏輯
return retVal;
}joinPoint.proceed() 會調(diào)用目標方法,或者是調(diào)用另一個切面。
雖然環(huán)繞通知可以實現(xiàn)另外幾種通知的功能,但在使用中都能實現(xiàn)功能的情況下,優(yōu)先使用其他通知方式。
4. 最終通知
最終通知在方法退出的時候執(zhí)行,使用 @After 注解定義,最終通知在方法正常退出和拋出異常時都會執(zhí)行,通常用于資源的釋放。
@After("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public void doAfter() {
// 自定義邏輯
}5. 異常通知
方法拋出異常的時候會執(zhí)行異常通知,使用 @AfterThrowing 定義異常通知。
@AfterThrowing("execution(* cn.codeartist.spring.aop.advice.*.*(..))")
public void doAfterThrowing() {
// 自定義邏輯
}注解的 throwing 屬性用來綁定目標方法拋出的異常,用于在通知中獲取目標方法拋出的異常實例。
@AfterThrowing(pointcut = "pointcut()", throwing = "ex")
public void doAfterThrowing(Throwable ex) {
// 自定義邏輯(通過參數(shù)綁定方法切入點方法拋出的異常)
}當注解使用了 throwing 屬性時,切入點會增加異常類型的限制,上面使用的 Throwable 類型可以匹配到所有異常類型。
例如下面的情況,異常通知的代碼不會被執(zhí)行:
// 目標方法
public void doServiceThrow() {
throw new RuntimeException("Test exception");
}
// 異常通知定義
@AfterThrowing(pointcut = "pointcut()", throwing = "ex")
public void doAfterThrowing(NullPointerException ex) {
// 目標方法拋出的是RuntimeException,參數(shù)綁定類型是NullPointerException,該通知不會被執(zhí)行
}三、通知的參數(shù)
在定義通知的方法簽名上可以指定參數(shù)來綁定目標方法的一些信息(例如前面講到的后置通知和異常通知)。
1. 切入點
在定義通知方法的時候,一般可以使用 JoinPoint 作為參數(shù),環(huán)繞通知使用 ProceedingJoinPoint。常用接口方法如下:
JoinPoint
public interface JoinPoint {
// 獲取代理對象
Object getThis();
// 獲取目標對象
Object getTarget();
// 獲取連接點方法的參數(shù)
Object[] getArgs();
// 獲取連接點方法的簽名
Signature getSignature();
}ProceedingJoinPoint
public interface ProceedingJoinPoint extends JoinPoint {
// 執(zhí)行下一個切面的通知或者目標方法
public Object proceed() throws Throwable;
// 執(zhí)行下一個切面的通知或者目標方法(帶參數(shù))
public Object proceed(Object[] args) throws Throwable;
}切面的切入點一般為方法,所以
Signature可以轉換為MethodSignature使用。
2. 通知的參數(shù)傳遞
通知的參數(shù)可以通過切點表達式 args 來指定,具體用法會在后面切點表達式詳解中講到。
@Before("pointcut() && args(name,..)")
public void doBefore(String name) {
// 切點表達式增加參數(shù)匹配
}args(name,..) 也會增加切入點的限制,目標方法的參數(shù)個數(shù)至少為一個,且第一個參數(shù)類型為 String。
四、通知的順序
Spring AOP 中一個目標類可以被多個切面切入,多個切面也可以切入一個目標類。 使用 @Order 注解來指定切面的優(yōu)先級,來控制切面的執(zhí)行順序。 在注冊切面 Bean 的時候指定 @Order,如下:
@Order(1)
@Aspect
@Component
public class FirstAspect {
// ......
}優(yōu)先級高的切面先執(zhí)行,通知執(zhí)行的順序如下:

可以得出:
- 優(yōu)先級高的切面,前置通知先執(zhí)行
- 優(yōu)先級低的切面,后置通知先執(zhí)行
Order值越小,優(yōu)先級越大。
Spring AOP 是基于動態(tài)代理的攔截器模式實現(xiàn)的,切面模型與攔截器模型相似,如下:

五、附錄
1. 常用注解
| 注解 | 描述 |
| @Aspect | 定義切面類 |
| @Before | 定義前置通知 |
| @AfterReturning | 定義后置通知 |
| @Around | 定義環(huán)繞通知 |
| @After | 定義最終通知 |
| @AfterThrowing | 定義異常通知 |
到此這篇關于SpringAOP中的通知Advice詳解的文章就介紹到這了,更多相關SpringAOP的通知內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springboot整合log4j的踩坑實戰(zhàn)記錄
log日志的重要性不言而喻,所以我們需要在系統(tǒng)內(nèi)根據(jù)實際的業(yè)務進行日志的整合,下面這篇文章主要給大家介紹了關于springboot整合log4j的踩坑實戰(zhàn)記錄,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2022-04-04

