news 2026/6/9 21:38:03

详解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/6/9 18:38:32

鸣潮自动化辅助工具完全指南

鸣潮自动化辅助工具完全指南 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸上锁合成 自动肉鸽 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves 一、核心价值:解放双手的游戏助手…

作者头像 李华
网站建设 2026/6/9 19:55:09

从律学发展到文本转语音|Supertonic极速TTS技术实践解析

从律学发展到文本转语音|Supertonic极速TTS技术实践解析 1. 引言:从音律演进到现代语音合成的工程启示 人类对声音的探索,始于对自然和谐的感知。早在数千年前,河姆渡遗址出土的骨笛已能演奏包含八度音程的旋律;古希…

作者头像 李华
网站建设 2026/6/9 21:25:35

NotaGen镜像深度体验|112种风格组合玩转AI作曲

NotaGen镜像深度体验|112种风格组合玩转AI作曲 在一次音乐创作工作坊的现场,一位青年作曲家尝试用AI辅助完成一段古典风格的小提琴协奏曲。他打开浏览器,选择“浪漫主义”时期、“柴可夫斯基”作曲家、“管弦乐”配置,点击生成—…

作者头像 李华
网站建设 2026/6/9 19:54:57

鸣潮自动化工具终极指南:10分钟快速上手

鸣潮自动化工具终极指南:10分钟快速上手 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸上锁合成 自动肉鸽 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves 鸣潮自动化工具是一款…

作者头像 李华
网站建设 2026/6/9 19:40:53

RevokeMsgPatcher防撤回终极指南:三步快速拦截所有被撤回消息

RevokeMsgPatcher防撤回终极指南:三步快速拦截所有被撤回消息 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: https://git…

作者头像 李华
网站建设 2026/6/9 19:52:30

Qwen1.5-0.5B-Chat WebUI配置:Flask流式交互部署教程

Qwen1.5-0.5B-Chat WebUI配置:Flask流式交互部署教程 1. 引言 1.1 学习目标 本文将带你从零开始,完整搭建一个基于 Qwen1.5-0.5B-Chat 模型的轻量级智能对话服务。通过本教程,你将掌握: 如何使用 ModelScope SDK 下载并加载通…

作者头像 李华