spring多個AOP執行先後順序(面試問題:怎麼控制多個aop的執行循序) 轉

衆所周知,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裏邊處理自己的業務邏輯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章