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