Spring AOP中增強Advice的執行順序
- Spring AOP中
Advice分類 - 同一
Apsect中不同型別Advice執行順序- 配置基礎環境
- 實驗結果
- 結論
- 不同
Aspect中Advice執行順序- 實驗一:
Aspect1為高優先級,Aspect2為低優先級- 實驗結果
- 實驗二:
Aspect1為低優先級,Aspect2為高優先級- 實驗結果
- 結論
- 實驗一:
- 參考資料:
本文主要驗證Spring AOP中Advice的執行順序問題,(Spring版本: 5.3.23)
Spring AOP中Advice分類
Spring AOP中Advice可分為如下五類:
@Around@Before@AfterReturning@AfterThrowing@After
Advice相關概念參考
同一Apsect中不同型別Advice執行順序
配置基礎環境
- 依賴版本
- Spring 版本為: 5.3.23
- Spring Boot 版本為: 2.6.12
- aspectjweaver 版本: 1.9.9.1
- 定義Spring Boot啟動類
package sakura.springinaction;
@SpringBootApplication
@EnableAspectJAutoProxy
public class MySpringApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringApplication.class, args);
}
}
- 定義一個用于測驗的Controller類
package sakura.springinaction.controller;
@Controller
@Slf4j
public class IndexController {
@GetMapping("/time")
@ResponseBody
public String time() {
LocalDateTime now = LocalDateTime.now();
String nowTime = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
log.info("Current time: " + nowTime);
return nowTime;
}
}
- 定義一個宣告式切面
Apsect1
@Slf4j
@Component
@Aspect
public class Aspect1 {
// 定義 Point Cut 切面
@Pointcut("execution(public * sakura.springinaction.controller.*.*(..))")
public void controllerLayer() {
}
// 定義Advice
@Before("controllerLayer()")
private void beforeAdvice2() {
log.info("Aspect_1 # @Before");
}
@After("controllerLayer() && @annotation(getMapping)")
private void afterAdvice1(GetMapping getMapping) {
log.info("Aspect_1 # @afterAdvice" + " path: " + Arrays.toString(getMapping.value()));
}
@AfterReturning(pointcut = "controllerLayer()", returning = "val")
private void afterReturningAdvice(Object val) {
log.info("Aspect_1 # @AfterReturning" + " returnValue: " + val);
}
@AfterThrowing(pointcut = "controllerLayer()", throwing = "thrower")
private void afterThrowingAdvice(Throwable thrower) {
log.info("Aspect_1 # @AfterThrowing" + " thrower: " + thrower.getClass().getName());
}
@Around("controllerLayer() && @annotation(getMapping)")
private Object aroundAdvice(ProceedingJoinPoint pjp, GetMapping getMapping) throws Throwable {
// Around 前置處理
Stopwatch stopwatch = Stopwatch.createStarted();
log.info("Aspect_1 # @Around-Before" + " methodName: " + pjp.getSignature().getName() + ", path: " + Arrays.toString(getMapping.value()));
Object result = pjp.proceed();
// Around 后置處理
log.info("Aspect_1 # @Around-After" + " methodName: " + pjp.getSignature().getName() + ", runTime: " + stopwatch.elapsed(TimeUnit.NANOSECONDS));
return result;
}
}
實驗結果
在 發起請求(http://localhost:8080/time) 后,日志輸出如圖:

結論
在同一個切面(Apsect)定義中對于同一個Join Point而言,不同型別的Advice執行先后順序依次是:
@Around前置處理@Before@AfterReturning/@AfterThrowing@After@Around后置置處理
優先級說明:
- 對于進入
Join Point的Advice而言(比如:@Around前置處理,@Before),優先級越高,越先執行;- 對于從
Join Point出來的Advice而言(比如:@Around后置處理,@After),優先級越高,越后執行;- 優先級從高到低依次為:
@Around,@Before,@After,@AfterReturning,@AfterThrowing;
PS:
如果在同一個切面(
Apsect)中定義了兩個同型別的Advice(比如定義兩個@Before), 對于某個Join Point而言這兩個Advice都匹配,那么這兩個Advice執行的先后順序是無法確定的,
不同Aspect中Advice執行順序
問: 當不同的Aspect中的Advice 都匹配到了同一個Join Point,那么那個Aspect中的Advice 先執行,那個后執行呢?
答: 不確定 ,但是可以通過在class上添加注解@Order指定優先級確定執行順序(參考檔案)
實驗一: Aspect1為高優先級,Aspect2為低優先級
- 與
Aspect1類似,再定義一個切面類Aspect2,如下
package sakura.springinaction.advice;
import org.springframework.core.annotation.Order;
@Slf4j
@Component
@Aspect
@Order(2)
public class Aspect2 {
// 定義Advice
@Before("sakura.springinaction.advice.Aspect1.controllerLayer()")
private void beforeAdvice2() {
log.info("Aspect_2 # @Before");
}
@After("sakura.springinaction.advice.Aspect1.controllerLayer() && @annotation(getMapping)")
private void afterAdvice1(GetMapping getMapping) {
log.info("Aspect_2 # @afterAdvice" + " path: " + Arrays.toString(getMapping.value()));
}
@AfterReturning(pointcut = "sakura.springinaction.advice.Aspect1.controllerLayer()", returning = "val")
private void afterReturningAdvice(Object val) {
log.info("Aspect_2 # @AfterReturning" + " returnValue: " + val);
}
@AfterThrowing(pointcut = "sakura.springinaction.advice.Aspect1.controllerLayer()", throwing = "thrower")
private void afterThrowingAdvice(Throwable thrower) {
log.info("Aspect_2 # @AfterThrowing" + " thrower: " + thrower.getClass().getName());
}
@Around("sakura.springinaction.advice.Aspect1.controllerLayer() && @annotation(getMapping)")
private Object aroundAdvice(ProceedingJoinPoint pjp, GetMapping getMapping) throws Throwable {
Stopwatch stopwatch = Stopwatch.createStarted();
log.info("Aspect_2 # @Around-Before" + " methodName: " + pjp.getSignature().getName() + ", path: " + Arrays.toString(getMapping.value()));
Object result = pjp.proceed();
log.info("Aspect_2 # @Around-After" + " methodName: " + pjp.getSignature().getName() + ", runTime: " + stopwatch.elapsed(TimeUnit.NANOSECONDS));
return result;
}
}
Aspect1添加@Order注解指定優先級,如下
@Slf4j
@Component
@Aspect
@Order(1)
public class Aspect1 {
//...
}
此時,Aspect1的優先級比Aspect2的優先級高,
實驗結果
實驗結果如下:

說明:
高優先級的
Aspect1中的@Around前置處理和@Before先于低優先級的Aspect2執行,而@AfterReturning,@After和@Around后置處理,則低優先級的Aspect2先執行,
實驗二: Aspect1為低優先級,Aspect2為高優先級
- 更改兩個
Aspect中@Order注解優先級,如下:
@Slf4j
@Component
@Aspect
@Order(2)
public class Aspect1 {
//...
}
@Slf4j
@Component
@Aspect
@Order(1)
public class Aspect2 {
//...
}
實驗結果
實驗結果如下:

結論
- 當不同的
Aspect中的Advice都匹配到了同一個Join Point,不同Aspect中的Advice執行順序不確定, - 通過在
Aspect類上添加注解@Order指定優先級,確定執行順序,執行順序滿足如下規律- 對于
@Around前置處理 和@Before兩種Advice而言,所在的Aspect優先級越高,越先執行 - 對于
@AfterReturning,@AfterThrowing,@After和@Around后置處理 型別的Advice而言,所在的Aspect優先級越高,越后執行
- 對于
參考資料:
- Aspect Oriented Programming with Spring
- AspectJ Programming Guide
本文主要目的是記錄學習程序,加深對知識點理解; 如有行文有誤,望指正,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/534117.html
標籤:其他
