聊聊 Spring AOP 的不为常知的“秘事”
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 里边处理自己的业务逻辑。
参考链接
- https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
- https://blog.csdn.net/rainbow702/article/details/52185827
聊聊 Spring AOP 的不为常知的“秘事”的更多相关文章
- Spring -- aop(面向切面编程),前置&后置&环绕&抛异常通知,引入通知,自动代理
1.概要 aop:面向方面编程.不改变源代码,还为类增加新的功能.(代理) 切面:实现的交叉功能. 通知:切面的实际实现(通知要做什么,怎么做). 连接点:应用程序执行过程期间,可以插入切面的地点. ...
- 从源码层面聊聊面试问烂了的 Spring AOP与SpringMVC
Spring AOP ,SpringMVC ,这两个应该是国内面试必问题,网上有很多答案,其实背背就可以.但今天笔者带大家一起深入浅出源码,看看他的原理.以期让印象更加深刻,面试的时候游刃有余. Sp ...
- Spring AOP常见面试题
一.AOP是什么? 与OOP对比,面向切面,传统的OOP开发中的代码逻辑是至上而下的过程中会长生一些横切性问题,这些横切性的问题和我们的主业务逻辑关系不会散落在代码的各个地方,造成难以维护,AOP的编 ...
- 死磕Spring之AOP篇 - Spring AOP常见面试题
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...
- 学习Spring5必知必会(5)~Spring AOP
一.学习 AOP 思想的准备工作: 1.横切面关注点 在开发中,为了给业务方法中增加日志记录,权限检查,事务控制等功能,此时我们需要在修改业务方法内添加这些零散的功能代码(横切面关注点). 这些零散存 ...
- 比较 Spring AOP 与 AspectJ
本文翻译自博客Comparing Spring AOP and AspectJ(转载:https://juejin.im/post/5a695b3cf265da3e47449471) 介绍 如今有多个 ...
- 关于 Spring AOP (AspectJ) 该知晓的一切
关联文章: 关于Spring IOC (DI-依赖注入)你需要知道的一切 关于 Spring AOP (AspectJ) 你该知晓的一切 本篇是年后第一篇博文,由于博主用了不少时间在构思这篇博文,加上 ...
- 关于 Spring AOP (AspectJ) 你该知晓的一切
版权声明:本文为CSDN博主「zejian_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/javazej ...
- Spring AOP源码分析--代理方式的选择
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! 年前写了一个面试突击系列的文章,目前只有redis相关的.在这个系列里,我整理了一些面试题与大家 ...
随机推荐
- 在NVIDIA A100 GPU上利用硬件JPEG解码器和NVIDIA nvJPEG库
在NVIDIA A100 GPU上利用硬件JPEG解码器和NVIDIA nvJPEG库 根据调查,普通人产生的1.2万亿张图像可以通过电话或数码相机捕获.这样的图像的存储,尤其是以高分辨率的原始格式, ...
- 【题解】SOFTWARE 二分+搜索/dp
题目描述 一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是 ...
- 【redis前传】自己手写一个LRU策略 | redis淘汰策略
title: 自己手写一个LRU策略 date: 2021-06-18 12:00:30 tags: - [redis] - [lru] categories: - [redis] permalink ...
- sql把一个字段中的特定字符替换成其他字符
将'0654879'替换成'0754879' UPDATE dbo.SG_Functionality SET FunctionalityCode=REPLACE(FunctionalityCode,' ...
- MVC,MVVM模式的理解
基本上,我们的产品就是通过接口从数据库中读取数据,然后将数据经过处理展示到用户看到的视图上.当然我们还可以从视图上读取用户的输入,然后通过接口写入到数据库.但是,如何将数据展示到视图上,又如何将用户的 ...
- 38、linux中软件的安装方法
38.1.rpm安装: rpm -ivh 包名# i:安装的软件: v:显示正在安装的软件信息: h:显示安装软件的进度: rpm -ql 包名 #查看安装包里的文件: rpm -qa 包名#查询包是 ...
- 『无为则无心』Python序列 — 24、Python序列的推导式
目录 1.列表推导式 (1)快速体验 (2)带if的列表推导式 (3)多个for循环实现列表推导式 2.字典推导式 (1)创建一个字典 (2)将两个列表合并为一个字典 (3)提取字典中目标数据 3.集 ...
- AcWing 1128. 信使
战争时期,前线有 n个哨所,每个哨所可能会与其他若干个哨所之间有通信联系. 信使负责在哨所之间传递信息,当然,这是要花费一定时间的(以天为单位). 指挥部设在第一个哨所.当指挥部下达一个命令后,指挥部 ...
- Network:java中文转byte出现负数问题
字节的释义 字节(Byte) 是计算机信息技术用于计量存储容量的一种计量单位,通常情况下 1字节 = 8位(bit),也表示一些计算机编程语言中的数据类型和语言字符. 字符与字节 ASCII码:1个英 ...
- Mybatis:Mybatis 逆向工程 generator配置
一.使用Maven方式引入Mybatis依赖Jar包(版本号自己改或定义)