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


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

眾所周知,spring聲明式事務是基於AOP實現的,那么,如果我們在同一個方法自定義多個AOP,我們如何指定他們的執行順序呢?網上很多答案都是指定order,order越小越是最先執行,這種也不能算是錯,但有些片面。

配置AOP執行順序的三種方式

通過實現org.springframework.core.Ordered接口

@Component  
@Aspect  
@Slf4j  
public class MessageQueueAopAspect1 implements Ordered{@Override  
    public int getOrder() {  
        // TODO Auto-generated method stub  
        return 2;  
    }  
      
} 

通過注解

@Component  
@Aspect  
@Slf4j  
@Order(1)  
public class MessageQueueAopAspect1{  
      
    ...  
} 

通過配置文件配置

<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>

同一個方法上加以下兩個AOP

測試代碼

@Component  
@Aspect  
@Slf4j  
public class MessageQueueAopAspect1 implements Ordered{  
      
    @Resource(name="actionMessageProducer")  
    private IProducer<MessageQueueInfo> actionProducer;     
      
    @Pointcut("@annotation(com.xxx.annotation.MessageQueueRequire1)")  
    private void pointCutMethod() {  
    }  
      
    //聲明前置通知  
    @Before("pointCutMethod()")  
    public void doBefore(JoinPoint point) {  
        log.info("MessageQueueAopAspect1:doBefore");  
        return;  
    }  
  
    //聲明后置通知  
    @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue")  
    public void doAfterReturning(JoinPoint point,Object returnValue) {  
        log.info("MessageQueueAopAspect1:doAfterReturning");  
    }  
  
    //聲明例外通知  
    @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")  
    public void doAfterThrowing(Exception e) {  
        log.info("MessageQueueAopAspect1:doAfterThrowing");  
    }  
  
    //聲明最終通知  
    @After("pointCutMethod()")  
    public void doAfter() {  
        log.info("MessageQueueAopAspect1:doAfter");  
    }  
  
    //聲明環繞通知  
    @Around("pointCutMethod()")  
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {  
        log.info("MessageQueueAopAspect1:doAround-1");  
        Object obj = pjp.proceed();  
        log.info("MessageQueueAopAspect1:doAround-2");  
        return obj;  
    }  
      
    @Override  
    public int getOrder() {  
        return 1001;  
    }  
} 
@Component  
@Aspect  
@Slf4j  
public class MessageQueueAopAspect2 implements Ordered{  
      
    @Resource(name="actionMessageProducer")  
    private IProducer<MessageQueueInfo> actionProducer;     
      
    @Pointcut("@annotation(com.xxx.annotation.MessageQueueRequire2)")  
    private void pointCutMethod() {  
    }  
      
      
    //聲明前置通知  
    @Before("pointCutMethod()")  
    public void doBefore(JoinPoint point) {  
        log.info("MessageQueueAopAspect2:doBefore");  
        return;  
    }  
  
    //聲明后置通知  
    @AfterReturning(pointcut = "pointCutMethod()", returning = "returnValue")  
    public void doAfterReturning(JoinPoint point,Object returnValue) {  
        log.info("MessageQueueAopAspect2:doAfterReturning");  
    }  
  
    //聲明例外通知  
    @AfterThrowing(pointcut = "pointCutMethod()", throwing = "e")  
    public void doAfterThrowing(Exception e) {  
        log.info("MessageQueueAopAspect2:doAfterThrowing");  
    }  
  
    //聲明最終通知  
    @After("pointCutMethod()")  
    public void doAfter() {  
        log.info("MessageQueueAopAspect2:doAfter");  
    }  
  
    //聲明環繞通知  
    @Around("pointCutMethod()")  
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {  
        log.info("MessageQueueAopAspect2:doAround-1");  
        Object obj = pjp.proceed();  
        log.info("MessageQueueAopAspect2:doAround-2");  
        return obj;  
    }  
      
    @Override  
    public int getOrder() {  
        return 1002;  
    }  
}  
@Transactional(propagation=Propagation.REQUIRES_NEW)  
@MessageQueueRequire1  
@MessageQueueRequire2  
public PnrPaymentErrCode bidLoan(String id){  
              ...  
       }  

測試結果

從上面的測試我們看到,確實是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里邊處理自己的業務邏輯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM