文档章节

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

o
 osc_n6euf5h6
发布于 2019/03/19 22:49
字数 715
阅读 9
收藏 0

转载: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里边处理自己的业务逻辑。

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

如何在Ruby中生成随机字符串 - How to generate a random string in Ruby

问题: I'm currently generating an 8-character pseudo-random uppercase string for "A" .. "Z": 我目前正在为“ A” ..“ Z”生成一个8个字符的伪随机大写字符串: value = ""; 8.times{......

法国红酒甜
51分钟前
20
0
Python中的mkdir -p功能[重复] - mkdir -p functionality in Python [duplicate]

问题: This question already has an answer here: 这个问题在这里已有答案: How can I safely create a nested directory? 如何安全地创建嵌套目录? 25 answers 25个答案 Is there a way...

技术盛宴
今天
15
0
原价500元的认证证书,限时免费考取!

本文作者:y****n 百度云智学院致力于为百度ABC战略(人工智能、大数据、云计算)提供人才生态体系建设,包括基于百度ABC、IoT的课程体系,整合百度优势技术能力的深度学习技术、Apollo无人车...

百度开发者中心
昨天
17
0
在virtualenv中使用Python 3 - Using Python 3 in virtualenv

问题: Using virtualenv , I run my projects with the default version of Python (2.7). 使用virtualenv ,我使用默认版本的Python(2.7)运行项目。 On one project, I need to use Pyth......

富含淀粉
今天
16
0
Python的__init__和self是做什么的? - What __init__ and self do on Python?

问题: I'm learning the Python programming language and I've came across something I don't fully understand. 我正在学习Python编程语言,遇到了一些我不太了解的东西。 In a method ......

javail
今天
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部