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

Spring AOP @AfterReturning (返回通知)的使用场景

在这里插入图片描述

核心定义

@AfterReturning 是 Spring AOP 中一个非常重要的通知(Advice类型。它的核心作用是:

仅在目标方法(连接点)成功执行正常返回之后,执行一段特定的逻辑。如果目标方法在执行期间抛出异常,则该通知不会被执行。

它就像是为一次成功的任务举行的“庆功会”或“成果验收”。只有当任务圆满完成(方法正常返回),这个后续步骤才会被触发。


@AfterReturning 的关键特性

  1. 执行时机:只在目标方法成功返回后执行。
  2. 访问返回值可以! 这是它与 @After (后置通知) 最核心的区别。@AfterReturning 的设计目的之一就是让我们能够获取并处理目标方法的返回值。
  3. 修改返回值不能! 这是一个非常重要的点。@AfterReturning 通知是在返回值已经生成并准备交还给调用者之后执行的,所以你可以在通知里读取它、记录它、或者基于它执行其他操作,但你无法直接修改这个返回值来影响最终的调用结果。如果需要修改返回值,必须使用功能更强大的 @Around (环绕通知)。

@AfterReturning 能做什么?(主要应用场景)

既然可以获取返回值,它的应用场景就非常明确了,主要集中在对“结果”的后处理上。

  1. 对返回结果进行日志记录

    • 这是最直接的应用。记录方法成功执行后返回了什么内容,对于调试和审计非常有用。
    • 示例:“方法 findUserById(101) 成功执行,返回值是 User{id=101, name='Alice'}”。
  2. 对返回结果进行二次处理或触发后续操作

    • 根据返回的结果,执行一些非侵入性的附加业务逻辑。
    • 示例:当一个“注册用户”的方法成功返回一个新的 User 对象后,@AfterReturning 通知可以获取到这个 User 对象,然后调用消息队列服务,发送一封欢迎邮件。这个“发送邮件”的逻辑与“注册用户”的核心业务解耦,非常清晰。
  3. 数据缓存

    • 当一个查询方法成功返回数据后,可以将这个返回结果存入缓存(如 Redis、Caffeine)。
    • 示例getProductById(id) 成功返回 Product 对象后,@AfterReturning 通知将这个 Product 对象以 id 为键存入缓存。
  4. 数据转换或格式化(用于日志或监控,而非修改)

    • 获取到返回值后,可以将其转换为特定的格式(如 JSON)再进行记录。

如何获取返回值?

要获取返回值,你需要在 @AfterReturning 注解中使用 returning 属性。

  • returning 属性的值是一个字符串,它指定了通知方法中哪个参数用来接收返回值。
  • 这个参数名必须与通知方法签名中的一个参数名完全匹配。

语法:

@AfterReturning(pointcut = "yourPointcut()", returning = "result")
public void myAdviceMethod(JoinPoint joinPoint, Object result) {// 'result' 参数就会接收到目标方法的返回值// 参数类型最好是 Object,以增加通用性
}

代码示例

让我们用一个例子来演示如何获取并处理返回值。

1. 业务服务类 (目标对象)

package com.example.service;import org.springframework.stereotype.Service;@Service
public class ProductService {// 成功返回一个字符串public String getProductById(long id) {System.out.println("--- 核心业务逻辑:正在查询产品 " + id + " ---");return "Product-" + id;}// 抛出异常的方法public void deleteProduct(long id) {System.out.println("--- 核心业务逻辑:正在删除产品 " + id + " ---");if (id <= 0) {throw new RuntimeException("产品ID无效,删除失败!");}System.out.println("产品 " + id + " 删除成功。");}
}

2. 切面类 (Aspect) 中定义 @AfterReturning 通知

package com.example.aop;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Aspect
@Component
public class ResultLoggingAspect {// 拦截 ProductService 中的所有公共方法@Pointcut("execution(public * com.example.service.ProductService.*(..))")public void productServicePointcut() {}/*** 定义返回通知* 1. 使用 @AfterReturning 注解* 2. 指定切点 "productServicePointcut()"* 3. 使用 returning = "returnValue" 来指定接收返回值的参数名*/@AfterReturning(pointcut = "productServicePointcut()", returning = "returnValue")public void logResult(JoinPoint joinPoint, Object returnValue) {String methodName = joinPoint.getSignature().getName();System.out.println("==================================================");System.out.printf("[AOP 返回通知]: 方法 [%s] 成功执行完成。%n", methodName);// 检查返回值类型,并进行处理if (returnValue != null) {System.out.printf("[AOP 返回通知]: 返回值为: [%s], 返回值类型为: %s%n",returnValue, returnValue.getClass().getName());// 在这里可以做更多事情,比如将 returnValue 存入缓存} else {// 对于 void 方法,returnValue 为 nullSystem.out.println("[AOP 返回通知]: 方法没有返回值 (void)。");}System.out.println("==================================================\n");}
}

3. 运行代码并观察输出

调用成功返回数据的方法 productService.getProductById(888L):

--- 核心业务逻辑:正在查询产品 888 ---
==================================================
[AOP 返回通知]: 方法 [getProductById] 成功执行完成。
[AOP 返回通知]: 返回值为: [Product-888], 返回值类型为: java.lang.String
==================================================

@AfterReturning 被触发,并成功获取到了返回值 "Product-888"

调用抛出异常的方法 productService.deleteProduct(-1L):

try {productService.deleteProduct(-1L);
} catch (Exception e) {System.err.println("调用方捕获到异常: " + e.getMessage());
}

输出:

--- 核心业务逻辑:正在删除产品 -1 ---
调用方捕获到异常: 产品ID无效,删除失败!

观察输出,你会发现没有任何关于 [AOP 返回通知] 的日志。这证明了当方法抛出异常时,@AfterReturning 通知是不会被执行的。

总结

特性描述
执行时机仅在目标方法成功执行并正常返回后。
核心用途对方法的返回结果进行后续处理,如日志记录、结果缓存、触发异步任务。
能否访问返回值可以,通过 returning 属性指定接收参数。
能否修改返回值不可以。如需修改,请使用 @Around 通知。
@After 的区别@After 总是执行(像 finally),而 @AfterReturning 只在成功时执行;@After 无法获取返回值,而 @AfterReturning 可以。
http://www.lryc.cn/news/572608.html

相关文章:

  • MySQL 分页查询列表;Explain ;深度分页 ;管理系统,筛选系统
  • AR 眼镜之-条形码识别-实现方案
  • 【AI时代速通QT】第二节:Qt SDK 的目录介绍和第一个Qt Creator项目
  • AI人工智能与LLM大语言模型有什么区别
  • Node.js 在前端开发中的作用与 npm 的核心理解
  • 1.22Node.js 中操作 Redis
  • Kafka线上集群部署方案:从环境选型到资源规划思考
  • 源易信息:领先GEO供应商的市场布局与服务优势
  • 【生活点滴】车辆过户、新车挂牌
  • 变幻莫测:CoreData 中 Transformable 类型面面俱到(五)
  • 学习华为 ensp 的学习心得体会
  • 百胜软件荣膺零售商业评论“《2024创新零售》优秀服务商TOP”奖项
  • 学习华为 ensp 的学习心得体会(适合新手)
  • Python 数据分析与可视化 Day 2 - 数据清洗基础
  • 如何轻松将照片从 iPhone 传输到 Android?
  • 从“数据困境”到“数据生态”:DaaS重塑三甲医院医疗数据治理
  • 【RTSP从零实践】2、使用RTP协议封装并传输H264
  • 基于Gold-YOLO的聚合-分发机制改进YOLOv8教程
  • 电影感户外柔和光线人像街拍摄影后期Lr调色教程,手机滤镜PS+Lightroom预设下载!
  • 【世纪龙科技】智能网联汽车装调仿真教学软件数智化赋能实训教学
  • 魅族“换血”出牌:手机基本盘站不稳,想靠AI和汽车“改命”
  • Servlet容器(Web容器)简介
  • Windows + R组合键常用命令
  • Qi无线充电:车载充电的便捷与安全之选
  • 大数据系统架构实践(一):Zookeeper集群部署
  • 分布式系统中的 Kafka:流量削峰与异步解耦(二)
  • Unity3d中使用Mirror进行自定义消息通信
  • 磐基PaaS平台MongoDB组件SSPL许可证风险与合规性分析(下)
  • 设计模式精讲 Day 8:组合模式(Composite Pattern)
  • Git——分布式版本控制工具