news 2026/1/27 6:56:10

详解Spring AOP五大通知类型:从零搭建企业级操作日志系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
详解Spring AOP五大通知类型:从零搭建企业级操作日志系统

AOP 日志记录实战

1. 概述

本文主要介绍基于 Spring AOP 的5 种通知类型实现统一日志记录的代码实战。

关于 AOP 的核心理论概念,请参考笔记 [[AOP面向切面编程]]。

核心思路
通过自定义注解标记需要记录日志的业务方法,利用 AOP 切面拦截带有该注解的方法,在方法执行的不同阶段(前置、后置、异常、环绕)输出日志信息。


2. 环境准备

2.1 定义目标方法

为了演示效果,我们先定义一个简单的 Controller 或 Service 方法作为连接点(Join Point)。

2.2 自定义注解

创建自定义注解@AopLogText,用于标记切入点并传递业务描述参数。
相关基础知识可参考 [[自定义注解]]。

packagecom.example.annotation;importjava.lang.annotation.*;@Target(ElementType.METHOD)// 作用范围:方法@Retention(RetentionPolicy.RUNTIME)// 生命周期:运行时保留(关键,否则AOP无法通过反射获取)@Documentedpublic@interfaceAopLogText{/** * 业务描述信息 * 例如:@AopLogText("用户登录") */Stringvalue()default"";}

3. 切面类实现

创建一个切面类,用于封装日志处理逻辑。

核心注解说明

  • @Aspect: 标记该类为一个切面类。
  • @Component: 将该类注册到 Spring 容器中,使其生效。
  • @Slf4j: (可选) Lombok 注解,用于快速使用日志对象log

3.1 定义切入点

这里直接使用@Pointcut定义通用的匹配规则,或者在通知注解中直接写表达式。
本例主要演示基于注解的切入方式:@annotation(com.example.annotation.AopLogText)


4. 通知类型详解与代码

4.1 前置通知 (Before)

在目标方法执行之前触发。常用于记录“开始执行某动作”及入参信息。

/** * 前置通知 * @param joinPoint 连接点对象,可获取方法签名、参数等信息 * @param aopLog 注解对象,通过参数绑定直接获取(注意参数名需匹配) */@Before("@annotation(aopLog)")publicvoidbeforeMethod(JoinPointjoinPoint,AopLogTextaopLog){// 1. 获取目标方法名StringmethodName=joinPoint.getSignature().getName();// 2. 获取注解上的参数值 (如: "开始查询")StringannotationValue=aopLog.value();log.info("[前置通知] 准备执行方法:{},业务描述:{}",methodName,annotationValue);}

4.2 返回通知 (AfterReturning)

在目标方法正常返回后触发。可以获取方法的返回值。

  • 注意:如果方法抛出异常,此通知不会执行。
/** * 返回通知 * @param joinPoint 连接点 * @param result 目标方法的返回值 (参数名必须与 returning 属性一致) */@AfterReturning(value="@annotation(com.example.annotation.AopLogText)",returning="result")publicvoidafterReturning(JoinPointjoinPoint,Objectresult){StringmethodName=joinPoint.getSignature().getName();log.info("[返回通知] 方法 {} 执行完成,返回值:{}",methodName,result);}

4.3 异常通知 (AfterThrowing)

在目标方法抛出异常时触发。可以获取具体的异常对象。

/** * 异常通知 * @param joinPoint 连接点 * @param ex 抛出的异常对象 (参数名必须与 throwing 属性一致) */@AfterThrowing(value="@annotation(com.example.annotation.AopLogText)",throwing="ex")publicvoidafterThrowing(JoinPointjoinPoint,Exceptionex){StringmethodName=joinPoint.getSignature().getName();log.error("[异常通知] 方法 {} 执行异常,原因:{}",methodName,ex.getMessage());}

4.4 最终通知 (After)

在目标方法执行之后触发。

  • 特点:无论方法是正常结束还是抛出异常,都会执行(类似于try-catch-finally中的finally块)。
@After("@annotation(com.example.annotation.AopLogText)")publicvoidafterMethod(JoinPointjoinPoint){StringmethodName=joinPoint.getSignature().getName();log.info("[最终通知] 方法 {} 执行结束(无论是否异常)",methodName);}

4.5 环绕通知 (Around)

功能最强大的通知类型。它包裹了目标方法,可以在方法执行前后自定义逻辑,甚至控制方法是否执行、修改返回值。

  • 适用场景:统计方法耗时、统一异常处理、事务控制。
/** * 环绕通知 * @param joinPoint ProceedingJoinPoint 是 JoinPoint 的子接口,增加了 proceed() 方法 * @param aopLogText 注解对象 * @return 目标方法的返回值 (必须返回,否则调用方收不到数据) */@Around("@annotation(aopLogText)")publicObjectaroundMethod(ProceedingJoinPointjoinPoint,AopLogTextaopLogText)throwsThrowable{StringmethodName=joinPoint.getSignature().getName();StringannotationValue=aopLogText.value();log.info("【环绕通知】开始执行方法:{},注解参数:{}",methodName,annotationValue);longstartTime=System.currentTimeMillis();Objectresult=null;try{// 核心:执行目标方法// result 为目标方法的返回值result=joinPoint.proceed();}catch(Throwablee){log.error("【环绕通知】方法 {} 执行异常:{}",methodName,e.getMessage());// 注意:通常需要将异常抛出,否则上层(如全局异常处理器)无法感知throwe;}finally{longcostTime=System.currentTimeMillis()-startTime;log.info("【环绕通知】方法 {} 执行耗时:{}ms",methodName,costTime);}// 必须返回结果returnresult;}


5. 关键细节:参数绑定

在 AOP 中获取注解参数时,有一种简便的参数绑定写法,无需通过反射手动解析。

操作步骤

  1. 在切入点表达式中指定参数名,例如@annotation(aopLog)
  2. 在通知方法的参数列表中声明同名的参数AopLogText aopLog

示意图

注意事项
切面方法中的参数名(如aopLog)必须与注解表达式@annotation(aopLog)中的名称严格一致,否则 Spring 无法完成映射。


6. 最佳实践

在实际项目中,应根据需求选择合适的通知类型:

  1. 基础日志记录

    • 推荐组合使用@Before(记录入参)、@AfterReturning(记录返回值)和@AfterThrowing(记录异常)。
    • 优点:职责单一,代码逻辑清晰,解耦性好。
  2. 复杂场景 / 性能监控

    • 推荐使用@Around
    • 场景:需要统计方法耗时(Start Time - End Time)、需要改变返回值、或者需要在一个上下文中同时处理入参和结果。
  3. 避免滥用@Around

    • 虽然环绕通知功能最强,但如果只是简单的打印日志,使用组合通知的可读性更高。
    • 环绕通知需要手动调用proceed()并处理异常,编写不当容易导致目标方法不执行或异常被吞没。

进阶扩展
在生产环境中,通常会将日志信息(操作人、时间、IP、耗时、结果)异步存储到数据库或发送到ELK(Elasticsearch, Logstash, Kibana) 系统中,以便进行审计和分析。

7. 参考文章与学习来源

  • 参考文章:Spring AOP 实现日志记录案例详解
  • 知识问答:亲爱的豆包老师
  • 笔记/术语优化:gemini-3-pro-preivew
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/16 6:25:10

RevokeMsgPatcher防撤回工具配置与使用完全指南

RevokeMsgPatcher防撤回工具配置与使用完全指南 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: https://gitcode.com/GitHub_Trending…

作者头像 李华
网站建设 2026/1/17 7:40:14

老电脑怎么跑大模型?UI-TARS云端方案1小时1块钱

老电脑怎么跑大模型?UI-TARS云端方案1小时1块钱 你是不是也遇到过这种情况:作为一名自由职业者,每天都要用笔记本处理各种任务,写方案、做设计、查资料。但手头这台五年前的旧笔记本越来越力不从心,打开几个网页就卡得…

作者头像 李华
网站建设 2026/1/20 6:45:38

5分钟部署Qwen3-Embedding-4B:零基础搭建多语言文本检索服务

5分钟部署Qwen3-Embedding-4B:零基础搭建多语言文本检索服务 1. 引言:为什么需要高效的文本嵌入服务? 在信息爆炸的时代,如何从海量非结构化文本中快速定位相关内容,已成为智能搜索、推荐系统和知识管理的核心挑战。…

作者头像 李华
网站建设 2026/1/26 23:28:58

鸣潮智能自动化终极攻略:效率翻倍的实战技巧

鸣潮智能自动化终极攻略:效率翻倍的实战技巧 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸上锁合成 自动肉鸽 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves 想要在鸣潮游戏中…

作者头像 李华
网站建设 2026/1/19 23:13:02

Zotero插件终极指南:打造高效文献管理系统的完整方案

Zotero插件终极指南:打造高效文献管理系统的完整方案 【免费下载链接】zotero-style zotero-style - 一个 Zotero 插件,提供了一系列功能来增强 Zotero 的用户体验,如阅读进度可视化和标签管理,适合研究人员和学者。 项目地址: …

作者头像 李华