聊聊 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相关的.在这个系列里,我整理了一些面试题与大家 ...
随机推荐
- RGB-D相机视觉SLAM
RGB-D相机视觉SLAM Dense Visual SLAM for RGB-D Cameras 开源代码地址: vision.in.tum.de/data/software/dvo 摘要 本文提 ...
- NVIDIA Nsight Systems CUDA 跟踪
NVIDIA Nsight Systems CUDA 跟踪 CUDA跟踪 NVIDIA Nsight Systems能够捕获有关在概要过程中执行CUDA的信息. 可以在报告的时间轴上收集和呈现以下信息 ...
- .NET平台系列22:.NET Core/.NET5/.NET6 对比 .NET Framework
系列目录 [已更新最新开发文章,点击查看详细] 在我的博客<.NET平台系列2 .NET Framework 框架详解>与 <.NET平台系列7 .NET Core 体系结构 ...
- 用 Flutter 和 Firebase 轻松构建 Web 应用
作者 / Very Good Ventures Team 我们 (Very Good Ventures 团队) 与 Google 合作,在今年的 Google I/O 大会上推出了 照相亭互动体验 ( ...
- teprunner重磅更新Git打通PyCharm与测试平台
经过Python测试交流群的小伙伴群策群力,teprunner添加了一个重要功能,把PyCharm中的代码,通过Git同步到测试平台中,生成测试用例.这样,teprunner就成了一个名副其实的pyt ...
- 【模拟7.14】建造游乐园(play)
这题是玄学的数论 首先考虑如何枚举偶数点度的图 可以考虑取出i-1个点 那么成图的数量为2^C(i-1,2) (原因单独取出的i点能平衡已建图中的奇数点,原因是某种性质....) 然后求带联通标号的欧 ...
- 「10.15」梦境(贪心)·玩具(神仙DP)·飘雪圣域(主席树\树状数组\莫队)
A. 梦境 没啥可说的原题.... 贪心题的常见套路我们坐标以左端点为第一关键字,右端点为第二关键字 然后对于每个转折点,我们现在将梦境中左端点比他小的区间放进$multiset$里 然后找最近的右端 ...
- VScode如何设置模板字符串html标签自动补全
在学习Vue的过程中,很多时候都需要用到模板字符串,但是里面的html标签一个字符一个字符的去敲未免也太麻烦了吧,其实我们可以通过设置来实现在模板字符串中按Tab键快速补全html标签. 1.在VSC ...
- ceph-csi源码分析(7)-rbd driver-IdentityServer分析
更多 ceph-csi 其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 ceph-csi源码分析(7)-rbd driver-IdentityServer分析 当 ...
- 7.7、深入解析openstak工作流程
1.openstack的使用: (1)使用openstack创建的用户默认是default域,角色是user; (2)域-->角色-->用户-->项目 (3)配额在管理员登录后再项目 ...