众所周知,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){
...
}


测试结果

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

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

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

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

结论

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

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