spring aop 执行顺序(@Before @Around @After @AfterReturning @AfterThrowing)

今天药忘吃喽~ 2024-04-06 12:24 172阅读 0赞

spring aop 执行顺序(@Before @Around @After @AfterReturning @AfterThrowing)

思路

通过单元测试,调用指定方法,验证切面方法执行顺序

代码

1.引入切面aop

  1. <!-- 切面 spring-boot-starter-aop -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-aop</artifactId>
  5. <version>2.6.2</version>
  6. </dependency>
  7. <parent>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-parent</artifactId>
  10. <version>2.7.0</version>
  11. <!-- <version>2.1.0.RELEASE</version>-->
  12. <!-- <version>2.0.0.RELEASE</version>-->
  13. <!-- <version>2.2.0.RELEASE</version>-->
  14. <!-- <version>2.3.0.RELEASE</version>-->
  15. <!-- <version>2.3.1.RELEASE</version>-->
  16. <!-- <version>2.3.2.RELEASE</version>-->
  17. <!-- <version>2.3.3.RELEASE</version>-->
  18. <!-- <version>1.5.22.RELEASE</version>-->
  19. <relativePath/> <!-- lookup parent from repository -->
  20. </parent>

2.目标方法
2.1目标方法A

  1. package com.example.temp.aopOrder;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.stereotype.Component;
  4. import javax.annotation.Resource;
  5. /**
  6. * @Author:
  7. * @Date:
  8. * @Version:1.0.0
  9. **/
  10. @Component
  11. @Slf4j
  12. public class AopOrderServiceA {
  13. @Resource
  14. AopOrderServiceB serviceB;
  15. public void aopOrderA() {
  16. log.info("aopOrderA-进入方法。。。");
  17. int x = 0/0;
  18. serviceB.aopOrderB();
  19. log.info("aopOrderA-方法执行完毕!");
  20. }
  21. }

2.2目标方法B

  1. package com.example.temp.aopOrder;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.stereotype.Component;
  4. /**
  5. * @Author:
  6. * @Date:
  7. * @Version:1.0.0
  8. **/
  9. @Component
  10. @Slf4j
  11. public class AopOrderServiceB {
  12. public void aopOrderB() {
  13. log.info("aopOrderB-进入方法。。。");
  14. // int x = 0/0;
  15. log.info("aopOrderB-方法执行完毕!");
  16. }
  17. }

3.切面方法

  1. package com.example.temp.aopOrder;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.*;
  5. import org.springframework.stereotype.Component;
  6. /**
  7. * @Author:
  8. * @Date:
  9. * @Version:1.0.0
  10. **/
  11. @Aspect// 这是一个切面
  12. @Component// 这是一个需要被装配的spring bean
  13. @Slf4j
  14. public class AopOrderAspecct {
  15. @Pointcut("execution(public void com.example.temp.aopOrder.*.*())")
  16. public void point() {
  17. }
  18. @Before("point()")
  19. public void before(JoinPoint joinPoint) {
  20. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  21. String methodName = methodSignature.getName();
  22. log.info("{}-执行before。。。", methodName);
  23. }
  24. @Around("point()")
  25. public void around(ProceedingJoinPoint joinPoint) {
  26. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  27. String methodName = methodSignature.getName();
  28. log.info("{}-进入around。。。", methodName);
  29. try {
  30. joinPoint.proceed();
  31. } catch (Throwable throwable) {
  32. log.error("{}-around内部方法执行失败:{}", methodName, throwable.getMessage());
  33. }
  34. log.info("{}-around执行完毕!", methodName);
  35. }
  36. @After("point()")
  37. public void after(JoinPoint joinPoint) {
  38. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  39. String methodName = methodSignature.getName();
  40. log.info("{}-执行after。。。", methodName);
  41. }
  42. @AfterReturning("point()")
  43. public void afterReturning(JoinPoint joinPoint) {
  44. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  45. String methodName = methodSignature.getName();
  46. log.info("{}-执行afterReturning。。。", methodName);
  47. }
  48. @AfterThrowing("point()")
  49. public void afterThrowing(JoinPoint joinPoint) {
  50. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  51. String methodName = methodSignature.getName();
  52. log.info("{}-执行afterThrowing。。。", methodName);
  53. }
  54. }

4.单元测试

  1. package com.example.temp.aopOrder;
  2. import org.junit.Test;
  3. import org.junit.runner.RunWith;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. import org.springframework.test.context.junit4.SpringRunner;
  6. import javax.annotation.Resource;
  7. /**
  8. * @Author:
  9. * @Date:
  10. * @Version:1.0.0
  11. **/
  12. @SpringBootTest
  13. @RunWith(SpringRunner.class)
  14. public class OrderServiceTest {
  15. @Resource
  16. AopOrderService aopOrderService;
  17. @Test
  18. public void testOrder() {
  19. String springVersion = SpringVersion.getVersion();
  20. String bootVersion = SpringBootVersion.getVersion();
  21. log.info("spring:{},springBoot:{}", springVersion, bootVersion);
  22. aopOrderService.aopOrder();
  23. }
  24. }

5.测试结果(执行环境springboot版本为2.7.0)
当目标方法无异常时

  1. spring:5.3.20,springBoot:2.7.0
  2. aopOrderA-进入around。。。
  3. aopOrderA-执行before。。。
  4. aopOrderA-进入方法。。。
  5. aopOrderA-方法执行完毕!
  6. aopOrderA-执行afterReturning。。。// 注意,这里不同
  7. aopOrderA-执行after。。。
  8. aopOrderA-around执行完毕!

当目标方法执行抛出异常时

  1. spring:5.3.20,springBoot:2.7.0
  2. aopOrderA-进入around。。。
  3. aopOrderA-执行before。。。
  4. aopOrderA-进入方法。。。
  5. aopOrderA-执行afterThrowing。。。// 注意,这里不同
  6. aopOrderA-执行after。。。
  7. aopOrderA-around内部方法执行失败:/ by zero
  8. aopOrderA-around执行完毕!

当目标方法切面嵌套时

  1. spring:5.3.20,springBoot:2.7.0
  2. aopOrderA-进入around。。。
  3. aopOrderA-执行before。。。
  4. aopOrderA-进入方法。。。
  5. aopOrderB-进入around。。。
  6. aopOrderB-执行before。。。
  7. aopOrderB-进入方法。。。
  8. aopOrderB-方法执行完毕!
  9. aopOrderB-执行afterReturning。。。
  10. aopOrderB-执行after。。。
  11. aopOrderB-around执行完毕!
  12. aopOrderA-方法执行完毕!
  13. aopOrderA-执行afterReturning。。。
  14. aopOrderA-执行after。。。
  15. aopOrderA-around执行完毕!
  16. aopOrderA-方法执行完毕!
  17. aopOrderA-执行afterReturning。。。
  18. aopOrderA-执行after。。。
  19. aopOrderA-around执行完毕!

6.不同版本的差异

springboot版本 2.3.1.RELEASE 之前,after在around之后执行, 2.3.1.RELEASE 及之后,around包裹整个切面执行周期

spring boot 版本为 2.0.0.RELEASE

  1. spring:5.0.4.RELEASE,springBoot:2.0.0.RELEASE
  2. aopOrderA-进入around。。。
  3. aopOrderA-执行before。。。
  4. aopOrderA-进入方法。。。
  5. aopOrderA-方法执行完毕!
  6. aopOrderA-around执行完毕!
  7. aopOrderA-执行after。。。
  8. aopOrderA-执行afterReturning。。。

spring boot 版本为 2.1.0.RELEASE

  1. spring:5.1.2.RELEASE,springBoot:2.1.0.RELEASE
  2. aopOrderA-进入around。。。
  3. aopOrderA-执行before。。。
  4. aopOrderA-进入方法。。。
  5. aopOrderA-方法执行完毕!
  6. aopOrderA-around执行完毕!
  7. aopOrderA-执行after。。。
  8. aopOrderA-执行afterReturning。。。

spring boot 版本为 2.2.0.RELEASE

  1. spring:5.2.0.RELEASE,springBoot:2.2.0.RELEASE
  2. aopOrderA-进入around。。。
  3. aopOrderA-执行before。。。
  4. aopOrderA-进入方法。。。
  5. aopOrderA-方法执行完毕!
  6. aopOrderA-around执行完毕!
  7. aopOrderA-执行after。。。
  8. aopOrderA-执行afterReturning。。。

spring boot 版本为 2.3.0.RELEASE

  1. spring:5.2.6.RELEASE,springBoot:2.3.0.RELEASE
  2. aopOrderA-进入around。。。
  3. aopOrderA-执行before。。。
  4. aopOrderA-进入方法。。。
  5. aopOrderA-方法执行完毕!
  6. aopOrderA-around执行完毕!
  7. aopOrderA-执行after。。。
  8. aopOrderA-执行afterReturning。。。

spring boot 版本为 2.3.1.RELEASE

  1. spring:5.2.7.RELEASE,springBoot:2.3.1.RELEASE
  2. aopOrderA-进入around。。。
  3. aopOrderA-执行before。。。
  4. aopOrderA-进入方法。。。
  5. aopOrderA-方法执行完毕!
  6. aopOrderA-执行afterReturning。。。
  7. aopOrderA-执行after。。。
  8. aopOrderA-around执行完毕!// 注意,这里不同

发表评论

表情:
评论列表 (有 0 条评论,172人围观)

还没有评论,来说两句吧...

相关阅读