news 2026/4/18 3:22:49

详解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/4/18 7:01:45

RevokeMsgPatcher微信QQTIM防撤回补丁终极配置指南

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

作者头像 李华
网站建设 2026/4/17 10:03:00

实测Qwen2.5极速版:1GB小模型实现打字机般流畅对话

实测Qwen2.5极速版:1GB小模型实现打字机般流畅对话 1. 引言 在边缘计算和本地部署场景中,大语言模型的轻量化与高效推理正成为关键需求。尽管千亿参数级别的模型在性能上表现出色,但其对硬件资源的高要求限制了在低算力设备上的应用。为此&…

作者头像 李华
网站建设 2026/4/18 3:27:23

Hadoop在毕业设计中的核心难点与实用价值

大数据方向毕业设计中,Hadoop因其生态完善、应用广泛,成为多数同学的首选技术栈,但实际落地中常遇各类坑点。本文梳理Hadoop毕设核心难点及对应解决方案,同时明确其在毕设中的核心作用,助力高效完成设计。一、 Hadoop在…

作者头像 李华
网站建设 2026/4/18 3:29:37

从零构建AI作曲系统|NotaGen大模型镜像全场景使用手册

从零构建AI作曲系统|NotaGen大模型镜像全场景使用手册 在人工智能加速渗透创意领域的今天,音乐创作正迎来一场静默的革命。传统上被视为人类情感与灵感专属的作曲行为,如今已可通过大语言模型(LLM)范式实现高质量符号…

作者头像 李华
网站建设 2026/4/17 23:12:27

国家中小学智慧教育平台电子课本下载工具完全指南

国家中小学智慧教育平台电子课本下载工具完全指南 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具 项目地址: https://gitcode.com/GitHub_Trending/tc/tchMaterial-parser 在数字化教育快速发展的时代背景下,获取高质量的官方…

作者头像 李华
网站建设 2026/4/18 3:25:45

Deep-Live-Cam终极指南:如何用一张图片实现实时人脸交换

Deep-Live-Cam终极指南:如何用一张图片实现实时人脸交换 【免费下载链接】Deep-Live-Cam real time face swap and one-click video deepfake with only a single image 项目地址: https://gitcode.com/GitHub_Trending/de/Deep-Live-Cam 在当今数字化时代&a…

作者头像 李华