Spring Boot 用 AOP 做方法级日志与耗时统计:@Around 切面实战
Spring Boot 用 AOP 做方法级日志与耗时统计:Around 切面实战排查线上慢接口时,最想知道的是「到底哪个方法慢」。最土的办法是在每个 Service 方法开头long start System.currentTimeMillis(),结尾算差值打日志。写三五个方法还行,几十个方法全手动埋点,代码里到处是和业务无关的计时噪声,还容易漏掉某个 return 分支导致日志不打。Spring AOP 就是干这个的:把「记日志、算耗时」这种横切关注点从业务代码里剥离,用一个切面统一织入。这篇手把手写一个Around切面,自动给指定方法打入参、出参、耗时和异常日志,顺带讲清几个新手必踩的坑。朴素写法:计时代码淹没业务先看手动埋点长什么样:publicOrdercreateOrder(LonguserId,BigDecimalamount){longstartSystem.currentTimeMillis();log.info(createOrder 入参 userId{}, amount{},userId,amount);try{OrderorderdoCreate(userId,amount);// 真正的业务就这一行log.info(createOrder 耗时 {}ms,System.currentTimeMillis()-start);returnorder;}catch(Exceptione){log.error(createOrder 异常,e);throwe;}}真正的业务只有doCreate一行,其余全是计时和日志。每个方法都这么写,重复且易错——比如某个 early return 分支忘了打耗时日志,排查时就断线了。第一步:引依赖,开一个自定义注解先加 AOP 依赖(Spring Boot 里一个 starter 搞定):dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-aop/artifactId/dependency我们不想给「所有方法」都织日志,而是想精确控制哪些方法要统计。用一个自定义注解当「标记」最清晰:importjava.lang.annotation.*;Target(ElementType.METHOD)// 只能标在方法上Retention(RetentionPolicy.RUNTIME)// 运行时可反射读到,AOP 才能识别publicinterfaceLogExecution{Stringvalue()default;// 可选:给这次统计起个业务名}Retention(RUNTIME)是关键——注解信息必须保留到运行时,切面才读得到。写成默认的CLASS级别,运行期就拿不到注解,切面永远不触发。第二步:写一个 Around 切面Around是环绕通知,能力最全:方法执行前后都能插代码,还能拿到入参、控制是否放行、捕获返回值和异常。importorg.aspectj.lang.ProceedingJoinPoint;importorg.aspectj.lang.annotation.Around;importorg.aspectj.lang.annotation.Aspect;importorg.aspectj.lang.reflect.MethodSignature;importorg.slf4j.*;importorg.springframework.stereotype.Component;importjava.util.Arrays;AspectComponent// 必须交给 Spring 管理,切面才生效publicclassLogExecutionAspect{privatestaticfinalLoggerlogLoggerFactory.getLogger(LogExecutionAspect.class);// 切点:所有标了 LogExecution 的方法Around(annotation(logExecution))publicObjectaround(ProceedingJoinPointpjp,LogExecutionlogExecution)throwsThrowable{MethodSignaturesig(MethodSignature)pjp.getSignature();StringnamelogExecution.value().isEmpty()?sig.getMethod().getName()// 没起名就用方法名:logExecution.value();log.info([{}] 入参: {},name,Arrays.toString(pjp.getArgs()));longstartSystem.currentTimeMillis();try{Objectresultpjp.proceed();// 放行,执行真正的业务方法longcostSystem.currentTimeMillis()-start;log.info([{}] 返回: {}, 耗时: {}ms,name,result,cost);returnresult;// 必须把结果原样返回}catch(Throwablee){longcostSystem.currentTimeMillis()-start;log.error([{}] 异常: {}, 耗时: {}ms,name,e.getMessage(),cost);throwe;// 必须重新抛出,别把异常吞了}}}两个「必须」划重点:pjp.proceed()的返回值必须原样 return。忘了 return,业务方法的结果就被切面吞掉,调用方永远拿到null。catch 里必须throw e重新抛。切面只是旁观记录,不该改变业务的异常语义。吞掉异常会让上层以为一切正常,是极隐蔽的 bug。第三步:在业务方法上贴注解ServicepublicclassOrderService{LogExecution(创建订单)publicOrdercreateOrder(LonguserId,BigDecimalamount){returndoCreate(userId,amount);// 业务干净了,埋点交给切面}}调用后日志自动产出:[创建订单] 入参: [1001, 99.90] [创建订单] 返回: Order(id8, ...), 耗时: 43ms业务代码回归纯净,计时和日志被切面统一接管。想给哪个方法加统计,贴个注解即可,再不用复制那堆System.currentTimeMillis()。最容易踩的坑:同类内部调用,切面不生效这是 Spring AOP 的头号陷阱。AOP 靠代理对象拦截方法,只有「从外部通过 Spring 注入的 bean 调进来」才会走代理。同一个类里 A 方法直接调用本类的 B 方法(this.B()),走的是原始对象,绕过了代理,切面不触发:ServicepublicclassOrderService{publicvoidbatchCreate(ListReqreqs){for(Reqr:reqs){createOrder(r.userId,r.amount);// this.createOrder,切面不生效!}}LogExecution(创建订单)publicOrdercreateOrder(LonguserId,BigDecimalamount){...}}batchCreate里调createOrder,日志一条都不打——因为是this自调用,没经过代理。解决办法有几种,最简单的是把被切的方法拆到另一个 bean里,通过注入调用:ServicepublicclassOrderService{privatefinalOrderCreatorcreator;// 注入另一个 beanpublicOrderService(OrderCreatorcreator){this.creatorcreator;}publicvoidbatchCreate(ListReqreqs){for(Reqr:reqs){creator.createOrder(r.userId,r.amount);// 走代理,切面生效}}}记住这条规律:AOP 只拦「跨 bean」的调用,同类自调用一律失效。这和 SpringTransactional、Async失效是同一个根因,理解一次受用三处。小结AOP 剥离横切关注点:日志、耗时、鉴权这类和业务无关的代码,用切面统一织入,业务方法回归纯净。自定义注解当开关:注解Retention必须是RUNTIME,配合Around(annotation(...))精确控制切哪些方法。Around两个必须:proceed()的返回值原样 return、catch 里重新throw,否则会吞返回值或吞异常。切面类要Aspect Component:交给 Spring 管理才生效。头号坑:同类自调用失效。AOP 靠代理拦截,this.method()绕过代理;把被切方法拆到另一个 bean、经注入调用即可。这和Transactional/Async自调用失效同源。一句话记忆:AOP 是给方法「套壳」记账的代理,注解标 RUNTIME、around 别吞返回值和异常、自调用记得走别的 bean。

相关新闻

魔兽争霸3优化插件WarcraftHelper:解锁高帧率与完美宽屏体验

魔兽争霸3优化插件WarcraftHelper:解锁高帧率与完美宽屏体验

魔兽争霸3优化插件WarcraftHelper:解锁高帧率与完美宽屏体验 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 魔兽争霸3作为经典的即时战略…

2026/8/6 11:44:37 阅读更多 →
IT项目管理的重要性与实践技巧

IT项目管理的重要性与实践技巧

引言IT项目管理的重要性意味着它不单是应用知识、调整就能和使用常规的工具、技术来帮助项目完成,IT项目经理要应对整个项目的生命周期中可能发生的集成、快速技术更新和版本升级等问题,但是有了熟练的实践技巧,IT项目经理可以自如的应对这些…

2026/8/6 11:44:37 阅读更多 →
终极指南:3分钟快速安装Android Studio中文语言包,告别英文界面困扰

终极指南:3分钟快速安装Android Studio中文语言包,告别英文界面困扰

终极指南:3分钟快速安装Android Studio中文语言包,告别英文界面困扰 【免费下载链接】AndroidStudioChineseLanguagePack AndroidStudio中文插件(官方修改版本) 项目地址: https://gitcode.com/gh_mirrors/an/AndroidStudioChineseLanguage…

2026/8/6 11:44:37 阅读更多 →

最新新闻

ARIMA模型在电价预测中的应用与Matlab实现

ARIMA模型在电价预测中的应用与Matlab实现

1. 项目概述:电价预测与ARIMA模型的价值电力市场价格的波动直接影响着发电企业、电网公司和终端用户的运营决策。传统电价预测方法往往依赖于简单的统计模型或专家经验,难以捕捉电价序列中的复杂时间依赖性。这正是ARIMA(自回归积分滑动平均&…

2026/8/6 12:35:02 阅读更多 →
专科生必学9款AI工具:降AI率实战指南

专科生必学9款AI工具:降AI率实战指南

1. 项目概述:专科生如何应对AI时代的工具选择挑战2026年毕业的专科生正面临前所未有的就业压力——AI技术正在重塑各行各业的基础岗位。作为从业多年的职业教育顾问,我发现一个关键现象:掌握合适的AI工具能显著降低被AI替代的风险&#xff08…

2026/8/6 12:35:02 阅读更多 →
THPX信号源:聚焦细节 看看外汇领域风控思路的关键维度

THPX信号源:聚焦细节 看看外汇领域风控思路的关键维度

在外汇行业语境里,表达越清晰、信息越透明,越容易建立稳定预期。在THPX信号源的外汇服务中,从公开信息与使用体验出发,梳理其更值得肯定的能力点与细节表现。在外汇相关服务中,读者最在意的通常是信息是否清楚、提示是…

2026/8/6 12:35:02 阅读更多 →
3分钟搞定:Windows上AirPods的终极优化方案

3分钟搞定:Windows上AirPods的终极优化方案

3分钟搞定:Windows上AirPods的终极优化方案 【免费下载链接】AirPodsDesktop ☄️ AirPods desktop user experience enhancement program, for Windows and Linux (WIP) 项目地址: https://gitcode.com/gh_mirrors/ai/AirPodsDesktop 还在为Windows电脑上Ai…

2026/8/6 12:35:02 阅读更多 →
AI防骚扰软件哪个好?铃智铃AI智能接听实测

AI防骚扰软件哪个好?铃智铃AI智能接听实测

AI防骚扰软件哪个好?铃智铃AI智能接听实测摘要:骚扰电话(推销、中介、诈骗)越来越频繁,单纯"静音"或"标记"已经不够。本文围绕"AI防骚扰软件哪个好"做实测分析,介绍以「铃智…

2026/8/6 12:35:02 阅读更多 →
配网两阶段鲁棒优化调度模型与CCG算法实践

配网两阶段鲁棒优化调度模型与CCG算法实践

1. 配网两阶段鲁棒优化调度模型概述电力系统配网调度是保障电网安全稳定运行的核心环节。随着新能源渗透率不断提高和负荷特性日趋复杂,传统确定性优化方法已难以应对源荷双侧的不确定性挑战。两阶段鲁棒优化调度模型正是为解决这一难题而提出的创新方法&#xff0c…

2026/8/6 12:34:02 阅读更多 →

日新闻

深入解析LimboAI C++内核:架构设计与性能优化实战

深入解析LimboAI C++内核:架构设计与性能优化实战

1. 项目概述:为什么我们需要深入LimboAI的C内核?如果你是一名使用Godot引擎的游戏开发者,尤其是对AI行为逻辑有较高要求的项目,那么LimboAI这个名字你大概率不会陌生。它作为Godot 4生态中一个备受瞩目的行为树与状态机插件&#…

2026/8/6 0:00:06 阅读更多 →
Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

Unity 2D游戏敌人AI系统:基于PlayMaker状态机与2D Toolkit的实战开发

1. 项目概述与核心思路大家好,我是老张,一个在游戏开发一线摸爬滚打了十多年的老码农。今天咱们接着聊《空洞骑士》风格2D动作游戏的Demo制作。上一期我们搭好了基础框架,处理了角色移动和碰撞,这一期,我们要让游戏世界…

2026/8/6 0:00:06 阅读更多 →
被动防火门市场前景发展趋势

被动防火门市场前景发展趋势

被动防火门依靠材质结构、密闭构造阻隔烟火蔓延,无需电控启动,是建筑被动消防系统核心构件,行业依托新规管控、城市更新、工业安全升级迎来稳定扩容,整体朝着合规化、专项化、低碳化、智能化方向发展。现阶段 GB12955‑2024 新版国…

2026/8/6 0:00:06 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/5 15:00:43 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/5 13:13:56 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/5 10:20:36 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/5 23:28:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/5 21:00:14 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/5 23:46:51 阅读更多 →