SpringAOP:对于同一个切入点,不同切面不同通知的执行顺序
目录
- 1. 问题描述
- 2. 结论
- 结论1:"对于同一个切入点,同一个切面不同类型的通知的执行顺序"
- 结论2:"对于同一个切入点,不同切面不同类型通知的执行顺序"
- 3. 测试
- 环境:SpringBoot 2.3.4.RELEASE
- 测试集合1:针对结论1,单个切面类的情况。
- 测试1:切入点正常执行完,无异常。
- 测试2:切入点抛出异常
- 测试3:@AfterReturning执行了注解属性returning,表示需要返回值
- 测试集合2:针对结论2,多个切面类的情况
- 4. 参考
- 5. 结语:如果对大家有帮助,请点赞支持。如果有问题随时在评论中指出,感谢。
1. 问题描述
在Spring AOP中,对于同一个切入点,可能会有多个切面多种不同类型的通知共同作用于它,那么这些来自不同切面的不同类型通知,它们的执行顺序是怎样的?本文将答案分成2部分讲述。
- 对于同一个切入点,同一个切面不同类型的通知的执行顺序。
- 对于同一个切入点,不同切面不同类型通知的执行顺序。
文章后续安排:section 2直接给出结论,图文结合,更好理解。section 3讲述测试过程。section 4讲述参考来源。大家可以根据自己需要查看相应部分,想看结论可以直接看section2。
2. 结论
结论1:“对于同一个切入点,同一个切面不同类型的通知的执行顺序”
- 图片描述
- 文字描述
@Around(before)
@Before
#切入点方法#
@AfterReturing/@AfterThrowing
(1. 假如有异常,执行@AfterThrowing。2. 假如没异常,
2.1 假如@AfterReturning中没有设置returning属性,@AfterReturning修饰的方法会被执行。
2.2 假如@AfterReturning中设置了returning属性,当切入点方法拥有返回值时,@AfterReturning修饰的方法会被执行,否则不执行)
@After (不管有没有异常,都执行)
@Around(after)
(1. 切入点方法抛出异常而且没有捕获,不执行。2. 切入点方法没有异常,或者异常被捕获,执行。)
结论2:“对于同一个切入点,不同切面不同类型通知的执行顺序”
- 图片描述
- 文字描述
切入点方法之前,优先级越高的切面的通知,越先被执行。
切入点方法之后,优先级越高的切面的通知,越后被执行。
切面优先级可以通过在切面类上的"定义注解@Order"或者”实现Ordered接口中的getOrder()决定”,值越小,优先级越高。
3. 测试
环境:SpringBoot 2.3.4.RELEASE
测试集合1:针对结论1,单个切面类的情况。
测试1:切入点正常执行完,无异常。
- 切面类:各种通知都有
@Component
@Aspect
public class CommonAspect1 {@Pointcut("execution(* cn.edu.szu.flow.control.service.UserService.*(..))")private void pointCut() {}@Around("pointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Around(before)");Object val = joinPoint.proceed();System.out.println("Around(after)");return val;}@Before("pointCut()")public void before() {System.out.println("Before");}@AfterReturning(value = "pointCut()")public void afterReturning() {System.out.println("AfterReturning");}@AfterThrowing("pointCut()")public void afterThrowing() {System.out.println("AfterThrowing");}@After("pointCut()")public void after() {System.out.println("After");}
}
- 切入点方法
@Service
public class UserService {public void addUser() {System.out.println("切入点方法执行......");}
- 调用切入点方法
@SpringBootApplication
public class FlowControlApplication {public static void main(String[] args) {SpringApplication.run(FlowControlApplication.class, args);}@Autowiredprivate UserService userService;@PostConstructpublic void postConstruct() {// --------------调用切入点方法--------------userService.addUser();}
}
- 结果:符合结论1
测试2:切入点抛出异常
- 切面类:和测试1相同
- 切入点方法:在测试1基础上修改,让它抛出异常。
@Service
public class UserService {public void addUser() {System.out.println("切入点方法执行......");System.out.println("切入点方法抛出异常......");int i = 1/0;}
- 调用切入点方法:和测试1相同
- 结果:符合结论1。AfterThrowing执行,AfterReturning不执行,Around没有捕获异常,因此后面的不执行。
测试3:@AfterReturning执行了注解属性returning,表示需要返回值
- 切面类:在测试1基础上,只修改@AfterReturning
@AfterReturning(value = "pointCut()", returning = "result")
public void afterReturning(String result) {System.out.println("AfterReturning");
}
- 切入点方法:不抛出异常
@Service
public class UserService {public void addUser() {System.out.println("切入点方法执行......");}
- 调用切入点方法:和测试1相同
- 结果:符合结论1。@AfterReturning不执行,因为切入点方法是void,而@AfterReturning指明了需要返回值。
测试集合2:针对结论2,多个切面类的情况
- 切面1:包含不同类型的通知,并使用@Order指明优先级。值越小,优先级越高。
@Order(0)
@Component
@Aspect
public class CommonAspect1 {@Pointcut("execution(* cn.edu.szu.flow.control.service.UserService.*(..))")private void pointCut() {}@Around("pointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Around(before).One");Object val = joinPoint.proceed();System.out.println("Around(after).One");return val;}@Before("pointCut()")public void before() {System.out.println("Before.One");}@AfterReturning(value = "pointCut()")public void afterReturning() {System.out.println("AfterReturning.One");}@AfterThrowing("pointCut()")public void afterThrowing() {System.out.println("AfterThrowing.One");}@After("pointCut()")public void after() {System.out.println("After.One");}
}
- 切面2:和切面1类似,包含不同类型的通知,并使用@Order指明优先级。值越小,优先级越高。
@Order(1)
@Component
@Aspect
public class CommonAspect2 {@Pointcut("execution(* cn.edu.szu.flow.control.service.UserService.*(..))")private void pointCut() {}@Around("pointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Around(before).Two");Object val = joinPoint.proceed();System.out.println("Around(after).Two");return val;}@Before("pointCut()")public void before() {System.out.println("Before.Two");}@AfterReturning(value = "pointCut()")public void afterReturning() {System.out.println("AfterReturning.Two");}@AfterThrowing("pointCut()")public void afterThrowing() {System.out.println("AfterThrowing.Two");}@After("pointCut()")public void after() {System.out.println("After.Two");}
}
- 切入点方法
@Service
public class UserService {public void addUser() {System.out.println("切入点方法执行......");}
- 执行切入点方法
@SpringBootApplication
public class FlowControlApplication {public static void main(String[] args) {SpringApplication.run(FlowControlApplication.class, args);}@Autowiredprivate UserService userService;@PostConstructpublic void postConstruct() {// --------------调用切入点方法--------------userService.addUser();}
}
- 符合结论2:在切入点方法之前,优先级高的先执行。在切入点方法之后,优先级高的后执行。
- 调换2个切面的优先级:让切面2的优先级更高
- 结果:符合结论2。在切入点方法之前,优先级高的先执行。在切入点方法之后,优先级高的后执行。
4. 参考
- Spring 5.3.39 docs
本文测试使用SpringBoot2.3.4.RELEASE,内部使用的是Spring5.x,所以这里看的也是5.x的文档(Spring6.x文档关于这部分的内容和Spring5.x是一样的)。
- 参考1说:在切入点方法之前,优先级越高的通知越先执行。在切入点访问之后,优先级越高的通知越后执行。
- 参考2说:在不同的切面中,可以通过给切面类”添加@Order”或者”实现Ordered接口”来指定切面的优先级,从而决定不同切面中通知的优先级。如果不指定,则执行顺序不可知。
- 参考3说:在同一个切面中,不同类型的通知优先级由高到低分别是@Around, @Before, @After, @AfterReturning, @AfterThrowing。注意,结合参考1,@After和@AfterReturning, @AfterThrowing都是在切入点之后执行的,优先级越高的通知越后执行,因此执行顺序是@AfterThrowing,@AfterReturning,@After。
- 结合参考1+参考3+上述测试 得出结论1。
- 结合参考1+参考2+上述测试 得出结论2。
- 同一切面内通知的执行顺序:细节不多,但启发了我直接去看官方文档。
5. 结语:如果对大家有帮助,请点赞支持。如果有问题随时在评论中指出,感谢。
相关文章:

SpringAOP:对于同一个切入点,不同切面不同通知的执行顺序
目录 1. 问题描述2. 结论结论1:"对于同一个切入点,同一个切面不同类型的通知的执行顺序"结论2:"对于同一个切入点,不同切面不同类型通知的执行顺序" 3. 测试环境:SpringBoot 2.3.4.RELEASE测试集合…...
unique_ptr初始化
std::unique_ptr 是 C11 引入的智能指针,用于管理动态分配的对象的生命周期。unique_ptr 确保每个动态分配的对象有且仅有一个所有者,当 unique_ptr 超出作用域时,它会自动释放其管理的对象。以下是 std::unique_ptr 的一些常见初始化方法。 …...

HelloCTF [RCE-labs] Level 8 - 文件描述和重定向
开启靶场,打开链接: GET传参cmd system($cmd.">/dev/null 2>&1"); 这行代码将执行命令 $cmd,并且将其标准输出和标准错误输出都重定向到 /dev/null,这意味着无论命令的输出还是可能产生的错误信息都不会显示…...

DEVOPS: 集群伸缩原理
概述 阿里云 K8S 集群的一个重要特性,是集群的节点可以动态的增加或减少有了这个特性,集群才能在计算资源不足的情况下扩容新的节点,同时也可以在资源利用 率降低的时候,释放节点以节省费用理解实现原理,在遇到问题的…...
什么是SMO算法
SMO算法(Sequential Minimal Optimization) 是一种用于求解 支持向量机(SVM) 二次规划对偶问题的优化算法。它由 John Platt 在 1998 年提出,目的是快速解决 SVM 的优化问题,特别是当数据集较大时ÿ…...

MySQL根据.idb数据恢复脚本,做成了EXE可执行文件
文章目录 1.代码2.Main方法打包3.Jar包打成exe可执行文件4.使用(1.)准备一个表结构一样得数据库(2.)打开软件(3.)输入路径 5.恢复成功 本文档只是为了留档方便以后工作运维,或者给同事分享文档内…...
Spring Boot面试题
1.什么是SpringBoot?它的主要特点是什么? Spring Boot 是一个基于 Spring 框架的开发和构建应用程序的工具,它旨在简化 Spring 应用的初始搭建和开发过程。Spring Boot 提供了一种约定优于配置的方式,通过自动配置和默认值&#…...
原生页面引入Webpack打包JS
Webpack简介 概述: Webpack是一个现代JavaScript应用程序的静态模块打包器。它将应用程序中的每个文件视为一个模块,并通过配置规则来解析这些模块之间的依赖关系,最终将其打包成一个或多个浏览器可以执行的文件。动态加载(Code …...

健康之路押注医药零售:毛利率下滑亏损扩大,医疗咨询人次大幅减少
《港湾商业观察》黄懿 2024年9月13日,健康之路股份有限公司(下称“健康之路”)再次递表港交所,建银国际为独家保荐人。健康之路国内运营主体为健康之路(中国)信息技术有限公司和福建健康之路信息技术有限公…...
【人工智能-初级】第7章 聚类算法K-Means:理论讲解与代码示例
文章目录 一、K-Means聚类简介二、K-Means 聚类的工作原理2.1 初始化簇中心2.2 分配簇标签2.3 更新簇中心2.4 迭代重复2.5 K-Means 算法的目标三、K-Means 聚类的优缺点3.1 优点3.2 缺点四、K 值的选择五、Python 实现 K-Means 聚类5.1 导入必要的库5.2 生成数据集并进行可视化…...

HOT 100 技巧题(136/169/75/31/287)
136. 只出现一次的数字 技巧类型题目,通过异或运算实现 169. 多数元素 三种常见解法:1. 哈希2. 排序3. 投票法 75. 颜色分类 单指针 两次遍历:第一次遍历把所有0都交换到前面,记录最后一个0的位置index,第二次遍…...
什么是时间戳?怎么获取?有什么用?
在 JavaScript 中,时间戳通常表示为自 1970 年 1 月 1 日 00:00:00 UTC 以来的毫秒数。我们可以使用 Date 对象来获取当前时间的时间戳,或者将特定的日期转换为时间戳。在JavaScript中,时间戳通常以毫秒为单位表示。 如何获取时间戳 在Java…...
LeetCode:459重复的子字符串
给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例 2: 输入: s "aba" 输出: false示例 3: 输入: s "abcabcabcabc" 输…...

【含开题报告+文档+PPT+源码】基于SSM的旅游与自然保护平台开发与实现
开题报告 围场县拥有丰富的自然景观和野生动植物资源,同时面临着旅游业发展和自然保护之间的平衡问题,通过强调自然保护,这个平台可以教育游客如何尊重和保护当地的生态环境。同时,平台还可以提供关于生态保护的信息,…...

【ANTs】医疗影像工具ANTs多种安装方式教程
介绍ANTs的几种简单的安装教程 基于Releases的安装 Github上选择适配自己操作系统的安装包,链接: link 一般使用最新版本。这里官方操作说明,支持Ubuntu、MacOS、CentOS,但是windows有安装包,不知道怎么用。。。 下载后有两个文件夹,bin和lib,bin里面长这样(图示wind…...

想要音频里的人声,怎么把音频里的人声和音乐分开?
在音频处理领域,将音频中的人声和音乐分开是一个常见需求,尤其对于音乐制作、影视后期以及个人娱乐应用来说,这种分离技术显得尤为重要。随着科技的发展,现在已经有多种方法可以实现这一目的。 一、使用专业音频处理软件 市面上有…...

python代码中通过pymobiledevice3访问iOS沙盒目录获取app日志
【背景】 在进行业务操作过程中,即在app上的一些操作,在日志中会有对应的节点,例如,下面是查看设备实时视频过程对应的一些关键节点: 1、TxDeviceAwakeLogicHelper:wakeStart deviceId CxD2BA11000xxxx …...
Spring AOP 使用方法总结
AOP切面编程的最佳应用场景 记录日志性能监控事务管理处理异常数据验证,验证传入参数的正确性(一般不用这个方法做,而是用拦截器) spring提供了以下注解供开发者使用,编写AOP程序 Aspect 申明切面Pointcut 切点&#…...
LeetCode 每日一题 2024/10/21-2024/10/27
记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 10/21 910. 最小差值 II10/22 3184. 构成整天的下标对数目 I10/23 3185. 构成整天的下标对数目 II10/24 3175. 找到连续赢 K 场比赛的第一位玩家10/25 3180. 执行操作可获得…...

不到1500元的I卡可以玩转3A大作吗?撼与科技Intel Arc A750显卡游戏性能实
一、前言 还记得2022年10月的时候,英特尔发布了Arc A750和A770显卡,和此前所发布的DG1、A380不同,这两张显卡可以说是真正意义上的游戏显卡。不知不觉间,两年已经过去了,在这两年期间,英特尔不仅在积极地打…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...

PH热榜 | 2025-06-08
1. Thiings 标语:一套超过1900个免费AI生成的3D图标集合 介绍:Thiings是一个不断扩展的免费AI生成3D图标库,目前已有超过1900个图标。你可以按照主题浏览,生成自己的图标,或者下载整个图标集。所有图标都可以在个人或…...