Spring AOP 在我们日常开发中扮演了一个非常重要的角色,对于如何使用 AOP 相信很多人已经不陌生,但其中有一些点却容易被我们忽视,本节我们结合一些“不为常知”的问题展开讨论。

同一个 AOP 类中几个切面注解的执行顺序

先给出结论:@Around [joinPoint.proceed()前] —> @Before —> @Around [joinPoint.proceed()以及之后] —> @After —> @AfterReturning(如果有异常则@AfterThrowing) 。

话不多说,我这们直接上代码:

@Aspect
public class AopClass { @Pointcut(value = "execution(* io.alan.*.Klass.*dong(..))")
public void point() { } @Before(value = "point()")
public void before() {
System.out.println("========>begin klass dong... //2");
} @Around("point()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("========>around begin klass dong //1");
joinPoint.proceed();
System.out.println("========>around after klass dong //3");
} @After(value = "point()")
public void after() {
System.out.println("========>after klass dong... //4");
} @AfterReturning(value = "point()")
public void afterReturning() {
System.out.println("========>after klass dong... //5");
} }

查看应用打印的日志,如下:

不同 AOP 类切面的执行顺序

如果我们对同一个方法定义多个 AOP,它的执行顺序是什么样的呢?

配置 AOP 执行顺序的三种方式

方式1:实现 org.springframework.core.Ordered 接口
@Aspect
public class AopClass implements Ordered { @Override
public int getOrder() {
return 2;
} }
方式2:使用注解 @Order
@Aspect
@Order(2)
public class AopClass { }
方式3:使用配置文件
<aop:config expose-proxy="true">
<aop:aspect ref="aopBean" order="2">
<aop:pointcut id="testPointcut" expression="@annotation(xxx.xxx.xxx.annotation.xxx)"/>
<aop:around pointcut-ref="testPointcut" method="doAround" />
</aop:aspect>
</aop:config>

代码测试

下面我们演示在同一份代码上加上两个 AOP,然后观察日志。

@Aspect
@Order(2)
public class Aop2 { @Pointcut(value = "execution(* io.kimmking.*.Klass.*dong(..))")
public void point() { } @Before(value = "point()")
public void before() {
System.out.println(" Aop2========>before klass dong... //2");
} @AfterReturning(value = "point()")
public void afterReturning() {
System.out.println(" Aop2========>afterReturning klass dong... //5");
} @After(value = "point()")
public void after() {
System.out.println(" Aop2========>after klass dong... //4");
} @Around("point()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(" Aop2========>around before klass dong //1");
joinPoint.proceed();
System.out.println(" Aop2========>around after klass dong //3"); } }
@Aspect
@Order(3)
public class Aop3 { @Pointcut(value = "execution(* io.kimmking.*.Klass.*dong(..))")
public void point() { } @Before(value = "point()")
public void before() {
System.out.println(" Aop3========>before klass dong... //2");
} @AfterReturning(value = "point()")
public void afterReturning() {
System.out.println(" Aop3========>afterReturning klass dong... //5");
} @After(value = "point()")
public void after() {
System.out.println(" Aop3========>after klass dong... //4");
} @Around("point()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(" Aop3========>around before klass dong //1");
joinPoint.proceed();
System.out.println(" Aop3========>around after klass dong //3"); } }

打印的日志如下:

从日志中我们可以看到,order 越小的 AOP 类越先执行,但还有一点需要我们注意:就是最先执行的 AOP 最后才执行结束(如上图中的 AOP2)。

我们通过下面的这张示意图就可以理解了。

小结一下:我们可以将 Spring AOP 当作一个同心圆,要执行的方法为圆心,最外层的 order 最小。从最外层按照 AOP1、AOP2 的顺序依次执行 Around 方法,Before 方法。然后执行 method 方法,最后按照 AOP2、AOP1 (顺序反过来了)的顺序依次执行 After、AfterReturn 方法。

所以对多个AOP来说,先执行 before 的,一定后执行 after。

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

参考链接


END

聊聊 Spring AOP 的不为常知的“秘事”的更多相关文章

  1. Spring -- aop(面向切面编程),前置&后置&环绕&抛异常通知,引入通知,自动代理

    1.概要 aop:面向方面编程.不改变源代码,还为类增加新的功能.(代理) 切面:实现的交叉功能. 通知:切面的实际实现(通知要做什么,怎么做). 连接点:应用程序执行过程期间,可以插入切面的地点. ...

  2. 从源码层面聊聊面试问烂了的 Spring AOP与SpringMVC

    Spring AOP ,SpringMVC ,这两个应该是国内面试必问题,网上有很多答案,其实背背就可以.但今天笔者带大家一起深入浅出源码,看看他的原理.以期让印象更加深刻,面试的时候游刃有余. Sp ...

  3. Spring AOP常见面试题

    一.AOP是什么? 与OOP对比,面向切面,传统的OOP开发中的代码逻辑是至上而下的过程中会长生一些横切性问题,这些横切性的问题和我们的主业务逻辑关系不会散落在代码的各个地方,造成难以维护,AOP的编 ...

  4. 死磕Spring之AOP篇 - Spring AOP常见面试题

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  5. 学习Spring5必知必会(5)~Spring AOP

    一.学习 AOP 思想的准备工作: 1.横切面关注点 在开发中,为了给业务方法中增加日志记录,权限检查,事务控制等功能,此时我们需要在修改业务方法内添加这些零散的功能代码(横切面关注点). 这些零散存 ...

  6. 比较 Spring AOP 与 AspectJ

    本文翻译自博客Comparing Spring AOP and AspectJ(转载:https://juejin.im/post/5a695b3cf265da3e47449471) 介绍 如今有多个 ...

  7. 关于 Spring AOP (AspectJ) 该知晓的一切

    关联文章: 关于Spring IOC (DI-依赖注入)你需要知道的一切 关于 Spring AOP (AspectJ) 你该知晓的一切 本篇是年后第一篇博文,由于博主用了不少时间在构思这篇博文,加上 ...

  8. 关于 Spring AOP (AspectJ) 你该知晓的一切

    版权声明:本文为CSDN博主「zejian_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/javazej ...

  9. Spring AOP源码分析--代理方式的选择

    能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! 年前写了一个面试突击系列的文章,目前只有redis相关的.在这个系列里,我整理了一些面试题与大家 ...

随机推荐

  1. 【NX二次开发】Block UI对话框-代码生成部分

    常规: 语言:生成的代码语言 生成附注:是否生成注释代码 生成特定与块的代码: 输入点: 回调:对话框通过回调函数调用,例如通过另一个对话框的按钮调用本对话框 菜单:对话框通过菜单调用 用户出口:对话 ...

  2. 【UG二次开发】获取对象类型 UF_OBJ_ask_type_and_subtype

    代码: int type=0, subtype=0; UF_OBJ_ask_type_and_subtype(objTag, &type, &subtype);

  3. Spring Boot WebFlux-02——WebFlux Web CRUD 实践

    第02课:WebFlux Web CRUD 实践 上一篇基于功能性端点去创建一个简单服务,实现了 Hello.这一篇用 Spring Boot WebFlux 的注解控制层技术创建一个 CRUD We ...

  4. Flask一分钟Mock一个API

    如果安装了Python,并且安装了Flask: pip install flask 那么就可以在短短一分钟内Mock出来一个API,而且只需要用到一个文件. 彻底告别在线Mock网站无法指定请求方法, ...

  5. JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇

    JVM学习第一篇思考:一个Java代码是怎么运行起来的-上篇 作为一个使用Java语言开发的程序员,我们都知道,要想运行Java程序至少需要安装JRE(安装JDK也没问题).我们也知道我们Java程序 ...

  6. 可编程网络DataPath 及XDP

    目录 可编程网络DataPath XDP 的基本架构 XDP 的软件要求 XDP 的硬件要求 XDP 的工作流程及使用 XDP 的工作模式 XDP 的工作流程 Hello World XDP 的应用 ...

  7. MySQL到ClickHouse实时同步-CloudCanal实战

    简述 CloudCanal 近期实现了 MySQL(RDS) 到 ClickHouse 实时同步的能力,功能包含全量数据迁移.增量数据迁移.结构迁移能力,以及附带的监控.告警.HA等能力(平台自带). ...

  8. Spring Cloud 整合 Feign 的原理

    前言 在 上篇 介绍了 Feign 的核心实现原理,在文末也提到了会再介绍其和 Spring Cloud 的整合原理,Spring 具有很强的扩展性,会把一些常用的解决方案通过 starter 的方式 ...

  9. 全新安装Windows版 Atlassian Confluence 7.3.1 + MySQL 8.0,迁移数据,并设置服务自启

    Confluence是一个专业的企业知识管理与协同软件,也可以用于构建企业wiki.使用简单,但它强大的编辑和站点管理特征能够帮助团队成员之间共享信息.文档协作.集体讨论,信息推送. 安装Conflu ...

  10. bootstrap validate 验证插件 动态添加和动态删除验证项

    //添加验证项 function addField(field, notEmptyMsg, othercon) { if (!othercon) { $("#gyssave").b ...