首页IT科技springboot新增功能代码(Spring AOP中增强Advice的执行顺序)

springboot新增功能代码(Spring AOP中增强Advice的执行顺序)

时间2025-07-31 19:13:22分类IT科技浏览3555
导读:Spring AOP中增强Advice的执行顺序 Spring AOP中Advice分类 同一Apsect中不同类型Advice执行顺序 配置基础环境 实验结果 结论 不同Aspect中Advice执行顺序...

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

本文主要目的是记录学习过程,加深对知识点理解; 如有行文有误,望指正      。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
spring security自定义登录接口(Spring Security 自定义登录Session配置) 光山网址(光山在线论坛)