Spring AOP 通知的执行顺序

1. 结论

官方文档:Spring AOP Advice

故各种通知的执行顺序:

  • Spring版本5.2.7以后:
    • @Around环绕通知前置操作
    • @Before前置通知
    • 目标方法
    • @After后置通知
    • @AfterReturnin返回通知或@AfterThrowing异常通知
    • @Around环绕通知后置操作
  • Spring版本5.2.7一千:
    • @Around环绕通知前置操作
    • @Before前置通知
    • 目标方法
    • @Around环绕通知后置操作
    • @After后置通知
    • @AfterReturnin返回通知或@AfterThrowing异常通知

2. 示例

/*** 接口类*/
public interface CalculatorService {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);}
import com.example.aop.service.CalculatorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** 接口实现类*/
@Slf4j
@Component
public class CalculatorServiceImpl implements CalculatorService {@Overridepublic int add(int i, int j) {int result = i + j;log.info("方法内部 result = {}", result);// 为了测试效果,模拟异常信息// int a = 1/0;return result;}@Overridepublic int sub(int i, int j) {int result = i - j;log.info("方法内部 result ={} ", result);return result;}@Overridepublic int mul(int i, int j) {int result = i * j;log.info("方法内部 result ={} ", result);return result;}@Overridepublic int div(int i, int j) {int result = i / j;log.info("方法内部 result = {}", result);return result;}}

切面类

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** 自定义日志切面类** @author : Sakura* @className : LogAspect* @description : 日志切面类*/
@Component  // 交由IoC容器进行管理
@Aspect     // 声明为切面类
@Slf4j
public class LogAspect {// 设置切入点和通知类型/*** 前置通知:在被代理的目标方法前执行* 设置前置通知  @Before(value = "切入点表达式配置切入点")* 切入点表达式:* 下面切入点设置为:public int CalculatorImpl 所有方法 任意参数类型*/@Before(value = "execution(public int com.example.aop.service.impl.CalculatorServiceImpl.*(..))")public void beforeMethod(JoinPoint joinPoint) {// 使用JoinPoint获取方法签名、方法参数等相关信息// 获取方法名String methodName = joinPoint.getSignature().getName();// 获取方法参数Object[] args = joinPoint.getArgs();log.info("Logger--@Before前置通知,方法名称:{},方法参数:{}", methodName, Arrays.toString(args));}/*** 返回通知:在被代理的目标方法成功结束后执行* 设置返回通知:  @AfterReturning(value = "切入点表达式配置切入点", returning = "res")* res: 目标方法的返回结果*/@AfterReturning(value = "execution(public int com.example.aop.service.impl.CalculatorServiceImpl.*(..))", returning = "result")public void AfterReturningMethod(JoinPoint joinPoint, Object result) {// 使用JoinPoint获取方法签名、方法参数等相关信息// 获取方法名String methodName = joinPoint.getSignature().getName();// 获取方法参数Object[] args = joinPoint.getArgs();log.info("Logger--@AfterReturning返回通知,方法名称:{},方法参数:{},返回结果:{}", methodName, Arrays.toString(args), result);}/*** 后置通知:在被代理的目标方法最终结束后执行* 设置前置通知:  @After(value = "切入点表达式配置切入点")*/@After(value = "execution(public int com.example.aop.service.impl.CalculatorServiceImpl.*(..))")public void afterMethod(JoinPoint joinPoint) {// 使用JoinPoint获取方法签名、方法参数等相关信息// 获取方法名String methodName = joinPoint.getSignature().getName();// 获取方法参数Object[] args = joinPoint.getArgs();log.info("Logger--@After后置通知,方法名称:{},方法参数:{}", methodName, Arrays.toString(args));}/*** 异常通知:在被代理的目标方法异常结束后执行* 设置异常通知:  @AfterThrowing(value = "切入点表达式配置切入点", throwing = "ex")* ex: 代指异常信息*/@AfterThrowing(value = "execution(public int com.example.aop.service.impl.CalculatorServiceImpl.*(..))", throwing = "ex")public void afterThrowingMethod(JoinPoint joinPoint, Throwable ex) {// 使用JoinPoint获取方法签名、方法参数等相关信息// 获取方法名String methodName = joinPoint.getSignature().getName();log.info("Logger--@AfterThrowing异常通知,方法名称:" + methodName + ",异常信息:" + ex.getMessage());}/*** 环绕通知:使用try...catch...finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置* 设置异常通知:  @Around(value = "切入点表达式配置切入点)* 注:可以使用JoinPoint的子类 ProceedingJoinPoint 调用目标方法*/@Around(value = "execution(public int com.example.aop.service.impl.CalculatorServiceImpl.*(..))")public Object aroundMethod(ProceedingJoinPoint joinPoint) {// 使用JoinPoint获取方法签名、方法参数等相关信息// 获取方法名String methodName = joinPoint.getSignature().getName();// 获取方法参数Object[] args = joinPoint.getArgs();Object result = null;try {log.info("Logger--@Around环绕通知——目标方法执行之前");// 使用JoinPoint的子类 ProceedingJoinPoint 调用目标方法result = joinPoint.proceed();log.info("Logger--@Around环绕通知——目标方法执行之后");} catch (Throwable e) {e.printStackTrace();log.info("Logger--@Around环绕通知——目标方法出现异常执行");} finally {log.info("Logger--@Around环绕通知——目标方法执行完毕后执行");}return result;}}

测试:
当spring-aop版本为5.2.7.RELEASE:
目标方法正常执行

2024-07-08 17:06:54.148  INFO 260808 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行之前
2024-07-08 17:06:54.148  INFO 260808 --- [           main] com.example.aop.config.LogAspect         : Logger--@Before前置通知,方法名称:add,方法参数:[2, 3]
2024-07-08 17:06:54.154  INFO 260808 --- [           main] c.e.a.s.impl.CalculatorServiceImpl       : 方法内部 result = 5
2024-07-08 17:06:54.154  INFO 260808 --- [           main] com.example.aop.config.LogAspect         : Logger--@AfterReturning返回通知,方法名称:add,方法参数:[2, 3],返回结果:5
2024-07-08 17:06:54.154  INFO 260808 --- [           main] com.example.aop.config.LogAspect         : Logger--@After后置通知,方法名称:add,方法参数:[2, 3]
2024-07-08 17:06:54.154  INFO 260808 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行之后
2024-07-08 17:06:54.154  INFO 260808 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行完毕后执行

目标方法异常执行:

2024-07-08 17:06:05.156  INFO 320568 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行之前
2024-07-08 17:06:05.156  INFO 320568 --- [           main] com.example.aop.config.LogAspect         : Logger--@Before前置通知,方法名称:add,方法参数:[2, 3]
2024-07-08 17:06:05.162  INFO 320568 --- [           main] c.e.a.s.impl.CalculatorServiceImpl       : 方法内部 result = 5
2024-07-08 17:06:05.163  INFO 320568 --- [           main] com.example.aop.config.LogAspect         : Logger--@AfterThrowing异常通知,方法名称:add,异常信息:/ by zero
2024-07-08 17:06:05.163  INFO 320568 --- [           main] com.example.aop.config.LogAspect         : Logger--@After后置通知,方法名称:add,方法参数:[2, 3]
2024-07-08 17:06:05.163  INFO 320568 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法出现异常执行
2024-07-08 17:06:05.163  INFO 320568 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行完毕后执行
java.lang.ArithmeticException: / by zeroat com.example.aop.service.impl.CalculatorServiceImpl.add(CalculatorServiceImpl.java:19)at com.example.aop.service.impl.CalculatorServiceImpl$$FastClassBySpringCGLIB$$a70e6bfb.invoke(<generated>)

当spring-aop版本为5.2.6.RELEASE:
目标方法正常执行

2024-07-08 17:04:28.394  INFO 330008 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行之前
2024-07-08 17:04:28.394  INFO 330008 --- [           main] com.example.aop.config.LogAspect         : Logger--@Before前置通知,方法名称:add,方法参数:[2, 3]
2024-07-08 17:04:28.400  INFO 330008 --- [           main] c.e.a.s.impl.CalculatorServiceImpl       : 方法内部 result = 5
2024-07-08 17:04:28.400  INFO 330008 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行之后
2024-07-08 17:04:28.400  INFO 330008 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行完毕后执行
2024-07-08 17:04:28.400  INFO 330008 --- [           main] com.example.aop.config.LogAspect         : Logger--@After后置通知,方法名称:add,方法参数:[2, 3]
2024-07-08 17:04:28.401  INFO 330008 --- [           main] com.example.aop.config.LogAspect         : Logger--@AfterReturning返回通知,方法名称:add,方法参数:[2, 3],返回结果:5

目标方法异常执行,可以看到 5.2.6.RELEASE@Around通知导致异常被捕获了,没有触发 @AfterThrowing 通知,反而触发了 @AfterReturning 通知方法的执行;而5.2.7.RELEASE触发 了@AfterThrowing 通知

2024-07-08 17:04:57.640  INFO 315420 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行之前
2024-07-08 17:04:57.640  INFO 315420 --- [           main] com.example.aop.config.LogAspect         : Logger--@Before前置通知,方法名称:add,方法参数:[2, 3]
2024-07-08 17:04:57.647  INFO 315420 --- [           main] c.e.a.s.impl.CalculatorServiceImpl       : 方法内部 result = 5
2024-07-08 17:04:57.647  INFO 315420 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法出现异常执行
2024-07-08 17:04:57.648  INFO 315420 --- [           main] com.example.aop.config.LogAspect         : Logger--@Around环绕通知——目标方法执行完毕后执行
2024-07-08 17:04:57.648  INFO 315420 --- [           main] com.example.aop.config.LogAspect         : Logger--@After后置通知,方法名称:add,方法参数:[2, 3]
2024-07-08 17:04:57.648  INFO 315420 --- [           main] com.example.aop.config.LogAspect         : Logger--@AfterReturning返回通知,方法名称:add,方法参数:[2, 3],返回结果:null
java.lang.ArithmeticException: / by zeroat com.example.aop.service.impl.CalculatorServiceImpl.add(CalculatorServiceImpl.java:19)at com.example.aop.service.impl.CalculatorServiceImpl$$FastClassBySpringCGLIB$$a70e6bfb.invoke(<generated>)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/868676.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最新的 DL/T645 调试工具,工程师必备

分享一个好用的 DL/T645 调试工具&#xff0c;下载地址&#xff1a;https://www.redisant.cn/dl645master 文章目录 最新的 DL/T645 调试工具&#xff0c;工程师必备主要功能软件截图 最新的 DL/T645 调试工具&#xff0c;工程师必备 DL/T645 是中国电力行业的一个通信协议标准…

Day47:LeedCode1143.最长公共子序列 1035.不相交的线 53. 最大子序和 392.判断子序列

1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字…

解决uni-app中全局设置页面背景颜色只有部分显示颜色的问题

在页面的style标签设置了背景色但是只显示一部分 <style lang"scss"> .content{background-color: #f7f7f7;height: 100vh; } </style>我们在app.vue里设置就行了 注意一定要是**page{}** <style>/*每个页面公共css */page{background-color: #…

淘宝商品评论电商API接口:提升销量与用户评论的策略

一、API接口简介 淘宝商品评论电商API接口是淘宝开放平台提供的一项服务&#xff0c;联讯数据通过这个接口&#xff0c;商家可以获取关于自己商品的评论数据&#xff0c;包括评论内容、评分、买家等级等信息。这些数据可以帮助商家更好地了解消费者需求&#xff0c;优化商品和服…

724.力扣每日一题7/8 Java

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;算法练习关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 目录 思路 解题方法 时间复杂度 空间复杂度 Code 思路 主要基于数组的…

linux主机离线安装python3环境

一、下载好python版本 Index of /ftp/python/https://www.python.org/ftp/python/ 二、创建文件夹 mkdir /home/python/ 三、上传到主机 四、解压 # 解压xz得到tar包 xz -d Python-3.9.8.tar.xz # 解压tar包 tar -xvf Python-3.9.8.tar 五、指定安装路径 # 进入解压后的…

Java:StringJoiner 类

文章目录 一、概念二、StringJoiner 类 一、概念 StringJoiner 跟 StringBuilder一样&#xff0c;创建之后里面的内容是可变的&#xff0c;它可以非常高效的进行字符串拼接&#xff0c;代码编写简洁。 二、StringJoiner 类 import java.util.StringJoiner;public class Test …

【Python_GUI】tkinter常用组件——文本类组件

文本时窗口中必不可少的一部分&#xff0c;tkinter模块中&#xff0c;有3种常用的文本类组件&#xff0c;通过这3种组件&#xff0c;可以在窗口中显示以及输入单行文本、多行文本、图片等。 Label标签组件 Label组件的基本使用 Label组件是窗口中比较常用的组件&#xff0c;…

【LeetCode】有效的数独

目录 一、题目二、解法 一、题目 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&…

智能充电(新能源电动车,电单车)云管理系统的定制解决方案

一 系统简介 智能充电&#xff08;新能源电动车&#xff0c;电单车&#xff09;云管理系统 是一套能够实现对充电站/桩的实时通讯、状态监控、故障检测、运营分析、数据统计、策略设置的智能化多任务管理系统。 二 平台概览 智能充电云管理系统 https://chongdianzhuang.itg…

嵌入式Linux系统编程 — 7.4 fork、vfork函数创建子进程

目录 1 父进程与子进程概念 2 fork创建子进程 3 系统调用 vfork()函数 4 vfork与 fork函数如何选择 1 父进程与子进程概念 进程与子进程是操作系统中的一个基本概念&#xff0c;用于描述进程之间的层级关系。下面是对这一概念的简要说明&#xff1a; 父进程&#xff1a;在…

从项目中初识Autosar状态机转换

目录 0 前言 1 状态转换 1.1 BSM TO RMS 1.2 RMS TO RSS 1.3 RMS TO NOS 1.4 RSS TO PBSM 1.5 PBSM TO BSM 1.6 RSS TO NOS 1.7 RSS TO RMS 2 结尾 0 前言 之前在这篇《从项目中初识Autosar网络管理》已经和大家讲了Autosar网络管理的几个状态机以及定时器的大致概念&a…

Java:System 类

文章目录 一、概念二、常用方法2.1 exit()2.2 currentTimeMillis()2.3 arraycopy() 一、概念 System 类提供了对系统操作的一些方法&#xff0c;其中的方法都是静态的可以直接通过类名调用方法&#xff0c;构造方法是私有化无法实例化。 二、常用方法 2.1 exit() System.exi…

【网安播报】CocoaPods 曝关键漏洞,应用程序面临供应链攻击风险

1、CocoaPods 曝关键漏洞&#xff0c;数百万 macOS 和 iOS 应用程序面临供应链攻击风险 开源依赖管理器 CocoaPods 中的安全漏洞暴露了数千个软件包&#xff0c;利用这些漏洞的攻击者可以将恶意代码注入合法应用&#xff0c;通过受信任的渠道分发恶意软件&#xff0c;并破坏用户…

Qt QWizard新建向导实例

使用QWizard做新建向导&#xff0c;最简单的实例 class MyWizard : public QWizard { public: MyWizard(QWidget* parent nullptr); QWizardPage* createFirstPage(); QWizardPage* createSecondPage(); QWizardPage* createThirdPage(); }; MyWizard::MyWizard(QWidget* par…

最近点对问题(算法与数据结构设计)

课题内容和要求 最近点对问题&#xff0c;在二维平面上输入n个点列P。其中任一点pi&#xff08;xi&#xff0c;yi&#xff09;&#xff0c;编写程序求出最近的两个点。使用穷举法实现&#xff0c;算法复杂度O(n2)&#xff1b;优化算法&#xff0c;以O(nlog2n)实现这一问题 数…

【Hive实战】Linux磁盘空间不足导致HiveSession创建失败

磁盘空间不足导致HiveSession创建失败 文章目录 磁盘空间不足导致HiveSession创建失败问题描述堆栈关键字 处理方案确认服务器的磁盘使用情况寻找存储最大的目录和文件确认删除文件 问题描述 Hive的服务器&#xff08;Linux&#xff09;的磁盘空间不足&#xff0c;会导致与hiv…

静脉分割YOLOV8-SEG

静脉分割&#xff0c;YOLOV8*SEG资源-CSDN文库 首先使用YOLOV8-SEG训练&#xff0c;得到PT模型&#xff0c;然后转换成ONNX&#xff0c;OPENCV的DNN调用&#xff0c;从而摆脱PYTORCH依赖&#xff0c;支持C,PYTHON,ANDROID调用

Java信号量semaphore的原理与使用方法

Semaphore的基本概念 在Java中&#xff0c;Semaphore是位于java.util.concurrent包下的一个类。它的核心就是维护了一个许可集。简单来说&#xff0c;就是有一定数量的许可&#xff0c;线程需要先获取到许可&#xff0c;才能执行&#xff0c;执行完毕后再释放许可。 那么&…

《妃梦千年》第二十七章:宫中变故

第二十七章&#xff1a;宫中变故 在林清婉的精心策划和勇敢指挥下&#xff0c;边关的战局得到了暂时的缓解。尽管如此&#xff0c;她心中依然忧虑重重&#xff0c;敌人的阴谋层出不穷&#xff0c;随时可能再次袭来。为了进一步巩固宫中的安全&#xff0c;林清婉决定加强对宫中…