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/10/20 10:32:58 阅读更多 →
IT项目管理的重要性与实践技巧

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

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

2026/10/20 9:07:02 阅读更多 →
终极指南:3分钟快速安装Android Studio中文语言包,告别英文界面困扰

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

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

2026/10/21 1:17:18 阅读更多 →

最新新闻

Wireshark保存RTP包后变UDP?根因与修复方法详解

Wireshark保存RTP包后变UDP?根因与修复方法详解

你是不是也遇到过这种怪事:用Wireshark抓RTP包,明明实时预览的时候一切正常,顶部协议栏也明明白白写着“RTP”,但只要一保存文件再打开,RTP就变成了光秃秃的UDP。我之前排查一个语音网关的问题时,抓了一百多…

2026/10/21 5:12:04 阅读更多 →
AI事故频发的四大根因与系统防御策略

AI事故频发的四大根因与系统防御策略

1. 案例全景:十个引发广泛讨论的AI事故1.1 推荐算法放大虚假信息某大型内容平台曾发生一起标志性事件。一个不知名账号发布了一条完全虚构的所谓“重大新闻”,内容荒诞、错漏明显,但平台推荐引擎在几分钟内将它推送给数十万人。消息传到另一个…

2026/10/21 5:12:04 阅读更多 →
ADK-Python安全令牌传递机制:Agent身份穿越与防护实践

ADK-Python安全令牌传递机制:Agent身份穿越与防护实践

你们有没有遇到过这种情况:Agent 每执行一步都要去调第三方 API,令牌在工具函数里传了一圈,最后不知怎么就打到日志里了。我最早做多工具 Agent 的时候,就是这么把生产环境的 API Key 打满了一整个日志面板。标题里这个“Google A…

2026/10/21 5:12:04 阅读更多 →
Qt5下QFTP文件包接入实战:解决undefined reference与工程迁移

Qt5下QFTP文件包接入实战:解决undefined reference与工程迁移

简介:QT5移除了内置QFTP模块,使依赖FTP功能的开发者面临重新实现客户端能力的难题。这份资源正面向需要自建QT5 FTP模块的C开发者,提供一套可运行的QFTP实现,支持FTP连接、用户登录、服务器目录切换与列表获取,并留有扩…

2026/10/21 5:12:04 阅读更多 →
C++ union 的一种妙用法

C++ union 的一种妙用法

前言 union 是 C 时代留下来的少数几个「看起来简单、实际很容易用错」的语言设施之一。它的表面语义只有一句:所有成员共用同一块存储,同一时刻只有一个成员是「活的」。但「活的」这三个字在 C 里意味着对象的生命周期,而生命周期恰恰是很多…

2026/10/21 5:12:04 阅读更多 →
手写JSON解析器:从词法分析到语法树的编译原理实战

手写JSON解析器:从词法分析到语法树的编译原理实战

1. 从一段JSON文本到内存对象:解析器到底在做什么很多人第一次接触编译原理,都是从"写一个JSON解析器"开始的。这个选择很聪明——JSON的语法足够简单,简单到一页纸就能写完文法;但它又足够完整,完整到能覆盖…

2026/10/21 5:11:04 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/21 4:27:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →