spring多个AOP执行先后顺序(面试问题:怎么控制多个aop的执行循序)

2018/11/29 10:03
阅读数 7.2K

众所周知,spring声明式事务是基于AOP实现的,那么,如果我们在同一个方法自定义多个AOP,我们如何指定他们的执行顺序呢?网上很多答案都是指定order,order越小越是最先执行,这种也不能算是错,但有些片面。

 

  • 配置AOP执行顺序的三种方式:

 

  1. 通过实现org.springframework.core.Ordered接口[java] view plain copy
    1. @Component  
    2. @Aspect  
    3. @Slf4j  
    4. public class MessageQueueAopAspect1 implements Ordered{@Override  
    5.     public int getOrder() {  
    6.         // TODO Auto-generated method stub  
    7.         return 2;  
    8.     }  
    9.       
    10. }  
  2. 通过注解[java] view plain copy
    1. @Component  
    2. @Aspect  
    3. @Slf4j  
    4. @Order(1)  
    5. public class MessageQueueAopAspect1{  
    6.       
    7.     ...  
    8. }  
  3. 通过配置文件配置[html] view plain copy
    1. <aop:config expose-proxy="true">  
    2.     <aop:aspect ref="aopBean" order="0">    
    3.         <aop:pointcut id="testPointcut"  expression="@annotation(xxx.xxx.xxx.annotation.xxx)"/>    
    4.         <aop:around pointcut-ref="testPointcut" method="doAround" />    
    5.         </aop:aspect>    
    6. </aop:config>  

我们在同一个方法上加以下两个AOP,看看究竟。

 

[java] view plain copy

  1. @Component  
  2. @Aspect  
  3. @Slf4j  
  4. public class MessageQueueAopAspect1 implements Ordered{  
  5.       
  6.     @Resource(name="actionMessageProducer")  
  7.     private IProducer<MessageQueueInfo> actionProducer;     
  8.       
  9.     @Pointcut("@annotation(com.xxx.annotation.MessageQueueRequire1)")  
  10.     private void pointCutMethod() {  
  11.     }  
  12.       
  13.     //声明前置通知  
  14.     @Before("pointCutMethod()")  
  15.     public void doBefore(JoinPoint point) {  
  16.         log.info("MessageQueueAopAspect1:doBefore");  
  17.         return;  
  18.     }  
  19.   
  20.     //声明后置通知  
  21.     @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue")  
  22.     public void doAfterReturning(JoinPoint point,Object returnValue) {  
  23.         log.info("MessageQueueAopAspect1:doAfterReturning");  
  24.     }  
  25.   
  26.     //声明例外通知  
  27.     @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")  
  28.     public void doAfterThrowing(Exception e) {  
  29.         log.info("MessageQueueAopAspect1:doAfterThrowing");  
  30.     }  
  31.   
  32.     //声明最终通知  
  33.     @After("pointCutMethod()")  
  34.     public void doAfter() {  
  35.         log.info("MessageQueueAopAspect1:doAfter");  
  36.     }  
  37.   
  38.     //声明环绕通知  
  39.     @Around("pointCutMethod()")  
  40.     public Object doAround(ProceedingJoinPoint pjp) throws Throwable {  
  41.         log.info("MessageQueueAopAspect1:doAround-1");  
  42.         Object obj = pjp.proceed();  
  43.         log.info("MessageQueueAopAspect1:doAround-2");  
  44.         return obj;  
  45.     }  
  46.       
  47.     @Override  
  48.     public int getOrder() {  
  49.         return 1001;  
  50.     }  
  51. }  

[java] view plain copy

  1. @Component  
  2. @Aspect  
  3. @Slf4j  
  4. public class MessageQueueAopAspect2 implements Ordered{  
  5.       
  6.     @Resource(name="actionMessageProducer")  
  7.     private IProducer<MessageQueueInfo> actionProducer;     
  8.       
  9.     @Pointcut("@annotation(com.xxx.annotation.MessageQueueRequire2)")  
  10.     private void pointCutMethod() {  
  11.     }  
  12.       
  13.       
  14.     //声明前置通知  
  15.     @Before("pointCutMethod()")  
  16.     public void doBefore(JoinPoint point) {  
  17.         log.info("MessageQueueAopAspect2:doBefore");  
  18.         return;  
  19.     }  
  20.   
  21.     //声明后置通知  
  22.     @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue")  
  23.     public void doAfterReturning(JoinPoint point,Object returnValue) {  
  24.         log.info("MessageQueueAopAspect2:doAfterReturning");  
  25.     }  
  26.   
  27.     //声明例外通知  
  28.     @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")  
  29.     public void doAfterThrowing(Exception e) {  
  30.         log.info("MessageQueueAopAspect2:doAfterThrowing");  
  31.     }  
  32.   
  33.     //声明最终通知  
  34.     @After("pointCutMethod()")  
  35.     public void doAfter() {  
  36.         log.info("MessageQueueAopAspect2:doAfter");  
  37.     }  
  38.   
  39.     //声明环绕通知  
  40.     @Around("pointCutMethod()")  
  41.     public Object doAround(ProceedingJoinPoint pjp) throws Throwable {  
  42.         log.info("MessageQueueAopAspect2:doAround-1");  
  43.         Object obj = pjp.proceed();  
  44.         log.info("MessageQueueAopAspect2:doAround-2");  
  45.         return obj;  
  46.     }  
  47.       
  48.     @Override  
  49.     public int getOrder() {  
  50.         return 1002;  
  51.     }  
  52. }  

 

[java] view plain copy

  1. @Transactional(propagation=Propagation.REQUIRES_NEW)  
  2. @MessageQueueRequire1  
  3. @MessageQueueRequire2  
  4. public PnrPaymentErrCode bidLoan(String id){  
  5.               ...  
  6.        }  

看看执行结果:

从上面的测试我们看到,确实是order越小越是最先执行,但更重要的是最先执行的最后结束。

这个不难理解,spring AOP就是面向切面编程,什么是切面,画一个图来理解下:

         由此得出:spring aop就是一个同心圆,要执行的方法为圆心,最外层的order最小。从最外层按照AOP1、AOP2的顺序依次执行doAround方法,doBefore方法。然后执行method方法,最后按照AOP2、AOP1的顺序依次执行doAfter、doAfterReturn方法。也就是说对多个AOP来说,先before的,一定后after。

        如果我们要在同一个方法事务提交后执行自己的AOP,那么把事务的AOP order设置为2,自己的AOP order设置为1,然后在doAfterReturn里边处理自己的业务逻辑。

展开阅读全文
打赏
0
8 收藏
分享
加载中
更多评论
打赏
0 评论
8 收藏
0
分享
返回顶部
顶部