Spring--AOP、通知的执行顺序
多个切面的执行顺序
如果我们在同一个方法使用多个AOP注解,我们如何指定他们的执行顺序呢?
可以通过指定切面的order,order越小越是最先执行。
配置切面执行顺序的三种方式:
一.通过实现Ordered接口
@Component @Aspect @Slf4j public class MessageQueueAopAspect1 implements Ordered{@Override public int getOrder() { // TODO Auto-generated method stub return 2; } }
二.配置文件配置
<aop:config expose-proxy="true"> <aop:aspect ref="aopBean" order="0"> <aop:pointcut id="testPointcut" expression="@annotation(xxx.xxx.xxx.annotation.xxx)"/> <aop:around pointcut-ref="testPointcut" method="doAround" /> </aop:aspect> </aop:config>
三.@Order注解指定
@Component @Aspect @Slf4j @Order(1) public class MessageQueueAopAspect1{ ... }
通知的执行顺序
Advice :通知(建言),在切面的某个特定的连接点(增强方法)(Join point)上执行的操作。
分为:
测试示例
创建两个自定义注解
自定义注解1
1 /** 2 * 自定义注解1 3 * @author JustJavaIt 4 * @date 2022/3/20 21:09 5 */ 6 @Target(ElementType.METHOD) 7 @Retention(RetentionPolicy.RUNTIME) 8 @Documented 9 public @interface Annotation1 { 10 }
自定义注解2
1 /** 2 * 自定义注解2 3 * @author JustJavaIt 4 * @date 2022/3/20 21:09 5 */ 6 @Target(ElementType.METHOD) 7 @Retention(RetentionPolicy.RUNTIME) 8 @Documented 9 public @interface Annotation2 { 10 11 }
定义两个切面
切面1
1 /** 2 * 切面1 order比较小 先执行 3 * @author JustJavaIt 4 * @date 2022/3/20 21:13 5 */ 6 @Component 7 @Aspect 8 @Slf4j 9 @Order(1) 10 public class AopAspect1 { 11 12 @Pointcut("@annotation(com.study.frame.aopTest.Annotation1)") 13 private void pointCutMethod() { 14 } 15 16 /** 17 * 前置通知: 在一个方法执行之前,执行通知。 18 * 模拟执行权限检查 19 * @param point 20 */ 21 @Before("pointCutMethod()") 22 public void doBefore(JoinPoint point) { 23 log.info("AopAspect1:@Before,目标方法为:{},参数为{}", 24 point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName(), 25 Arrays.toString(point.getArgs())); 26 } 27 28 /** 29 * 返回后通知: 在一个方法执行之后,只有在方法成功完成时,才能执行通知。如果抛异常了,那么不会执行通知(可打开测试Controller注释)。 30 * @param point 31 * @param returnValue 32 */ 33 @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue") 34 public void doAfterReturning(JoinPoint point,Object returnValue) { 35 log.info("AopAspect1:@AfterReturning,方法返回值为:{}", returnValue); 36 } 37 38 /** 39 * 抛出异常后通知: 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。 40 * @param e 41 */ 42 @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e") 43 public void doAfterThrowing(Exception e) { 44 log.info("AopAspect1:@AfterThrowing"); 45 } 46 47 /** 48 * 后置通知:在一个方法执行之后,不考虑其结果,执行通知。 49 */ 50 @After("pointCutMethod()") 51 public void doAfter() { 52 log.info("AopAspect1:@After"); 53 } 54 55 /** 56 * 环绕通知: 在建议方法调用之前和之后,执行通知。 57 * @param pjp 58 * @return 59 * @throws Throwable 60 */ 61 @Around("pointCutMethod()") 62 public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 63 log.info("AopAspect1:@Around-1"); 64 Object obj = pjp.proceed(); 65 log.info("AopAspect1:@Around-2"); 66 return obj; 67 } 68 }
切面2
1 /** 2 * 切面2 order比较大 后执行 3 * @author JustJavaIt 4 * @date 2022/3/20 21:15 5 */ 6 @Component 7 @Aspect 8 @Slf4j 9 @Order(2) 10 public class AopAspect2 { 11 12 @Pointcut("@annotation(com.study.frame.aopTest.Annotation2)") 13 private void pointCutMethod() { 14 } 15 16 17 //声明前置通知 18 @Before("pointCutMethod()") 19 public void doBefore(JoinPoint point) { 20 log.info("AopAspect2:@Before,目标方法为:{},参数为{}", 21 point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName(), 22 Arrays.toString(point.getArgs())); 23 } 24 25 //声明后置通知 26 @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue") 27 public void doAfterReturning(JoinPoint point, Object returnValue) { 28 log.info("AopAspect2:@AfterReturning,方法返回值为:{}", returnValue); 29 } 30 31 //声明例外通知 32 @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e") 33 public void doAfterThrowing(Exception e) { 34 log.info("AopAspect2:@AfterThrowing"); 35 } 36 37 //声明最终通知 38 @After("pointCutMethod()") 39 public void doAfter() { 40 log.info("AopAspect2:@After"); 41 } 42 43 //声明环绕通知 44 @Around("pointCutMethod()") 45 public Object doAround(ProceedingJoinPoint pjp) throws Throwable { 46 log.info("AopAspect2:@Around-1"); 47 Object obj = pjp.proceed(); 48 log.info("AopAspect2:@Around-2"); 49 return obj; 50 } 51 }
测试单个切面(无异常)
@RestController @Slf4j @RequestMapping("/study") public class TestAopController { @Annotation1 @GetMapping("/testAop") public Boolean testAop(@RequestParam("user_id") Long userId) throws Exception { log.info("开始执行testAop()"); return true; } }
运行结果:
测试单个切面(抛异常)
1 @RestController 2 @Slf4j 3 @RequestMapping("/study") 4 public class TestAopController { 5 6 @Annotation1 7 @GetMapping("/testAop") 8 public Boolean testAop(@RequestParam("user_id") Long userId) throws Exception { 9 log.info("开始执行testAop()"); 10 throw new Exception("异常"); 11 } 12 }
运行结果:
测试多个切面(无异常)
1 @RestController 2 @Slf4j 3 @RequestMapping("/study") 4 public class TestAopController { 5 6 @Annotation1 7 @Annotation2 8 @GetMapping("/testAop") 9 public Boolean testAop(@RequestParam("user_id") Long userId) throws Exception { 10 log.info("开始执行testAop()"); 11 //throw new Exception("异常"); 12 return true; 13 } 14 }
运行结果:
测试多个切面(抛异常)
1 @RestController 2 @Slf4j 3 @RequestMapping("/study") 4 public class TestAopController { 5 6 @Annotation1 7 @Annotation2 8 @GetMapping("/testAop") 9 public Boolean testAop(@RequestParam("user_id") Long userId) throws Exception { 10 log.info("开始执行testAop()"); 11 throw new Exception("异常"); 12 } 13 }
运行结果:
总结
待补充 ......
希望本文章对您有帮助,您的转发、点赞是我的创作动力,十分感谢。
扫描下方二维码关注我,您会收到更多优质文章推送。
希望本文章对您有帮助,您的转发、点赞是我的创作动力,十分感谢。更多好文推荐,请关注我的微信公众号--JustJavaIt