当前位置: 首页 > news >正文

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部分讲述。

  1. 对于同一个切入点,同一个切面不同类型的通知的执行顺序。
  2. 对于同一个切入点,不同切面不同类型通知的执行顺序。

文章后续安排:section 2直接给出结论,图文结合,更好理解。section 3讲述测试过程。section 4讲述参考来源。大家可以根据自己需要查看相应部分,想看结论可以直接看section2。

2. 结论

结论1:“对于同一个切入点,同一个切面不同类型的通知的执行顺序”

  1. 图片描述
    在这里插入图片描述
  2. 文字描述

@Around(before)
@Before
#切入点方法#
@AfterReturing/@AfterThrowing
(1. 假如有异常,执行@AfterThrowing。2. 假如没异常,
2.1 假如@AfterReturning中没有设置returning属性,@AfterReturning修饰的方法会被执行。
2.2 假如@AfterReturning中设置了returning属性,当切入点方法拥有返回值时,@AfterReturning修饰的方法会被执行,否则不执行)
@After (不管有没有异常,都执行)
@Around(after)
(1. 切入点方法抛出异常而且没有捕获,不执行。2. 切入点方法没有异常,或者异常被捕获,执行。)

结论2:“对于同一个切入点,不同切面不同类型通知的执行顺序”

  1. 图片描述
    在这里插入图片描述
  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
    验证结论1-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没有捕获异常,因此后面的不执行。
    验证结论1-2

测试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指明了需要返回值。
    验证结论1-3

测试集合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-1
  • 调换2个切面的优先级:让切面2的优先级更高
    降低切面1优先级
    提升切面2优先级
  • 结果:符合结论2。在切入点方法之前,优先级高的先执行。在切入点方法之后,优先级高的后执行。
    验证结论2-2

4. 参考

  1. Spring 5.3.39 docs
    本文测试使用SpringBoot2.3.4.RELEASE,内部使用的是Spring5.x,所以这里看的也是5.x的文档(Spring6.x文档关于这部分的内容和Spring5.x是一样的)。
    Spring 5.3.39参考文档
  • 参考1说:在切入点方法之前,优先级越高的通知越先执行。在切入点访问之后,优先级越高的通知越后执行。
  • 参考2说:在不同的切面中,可以通过给切面类”添加@Order”或者”实现Ordered接口”来指定切面的优先级,从而决定不同切面中通知的优先级。如果不指定,则执行顺序不可知。
  • 参考3说:在同一个切面中,不同类型的通知优先级由高到低分别是@Around, @Before, @After, @AfterReturning, @AfterThrowing。注意,结合参考1,@After和@AfterReturning, @AfterThrowing都是在切入点之后执行的,优先级越高的通知越后执行,因此执行顺序是@AfterThrowing,@AfterReturning,@After。
  • 结合参考1+参考3+上述测试 得出结论1。
  • 结合参考1+参考2+上述测试 得出结论2。
  1. 同一切面内通知的执行顺序:细节不多,但启发了我直接去看官方文档。

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 的优化问题,特别是当数据集较大时&#xff…...

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不同,这两张显卡可以说是真正意义上的游戏显卡。不知不觉间,两年已经过去了,在这两年期间,英特尔不仅在积极地打…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

XCTF-web-easyupload

试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

ES6从入门到精通:前言

ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

【机器视觉】单目测距——运动结构恢复

ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛&#xf…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

浅谈不同二分算法的查找情况

二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况&#xf…...