用 AOP 记录 Web 接口进出参和耗时

zjc 于 2026-08-11 发布

排查接口问题时,最有价值的三条信息通常是:请求带来了什么、返回了什么、耗时多久。项目把这些信息统一放在 WebLogAspect,所有 @RestController 自动被拦截,业务代码不用手写日志。

一、切点只看 RestController

@Pointcut("@within(org.springframework.web.bind.annotation.RestController)")
public void controllerPointcut() {
}

https://github.com/springvortex/spring-cloud-alibaba/blob/main/service-common/src/main/java/com/zjc/common/aop/WebLogAspect.java

这个范围足够克制:只记录 HTTP 入口,不拦截 Service、Mapper 等内部调用,避免一次请求产生成倍的重复日志。

二、环绕通知统一记录开始和结束

方法执行前输出 HTTP 方法、URI、目标方法、参数;执行后输出耗时和结果;异常分支输出异常消息后继续抛出,交给 GlobalExceptionHandler 处理。

long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
log.info("<== cost={}ms", System.currentTimeMillis() - startTime);
return result;

https://github.com/springvortex/spring-cloud-alibaba/blob/main/service-common/src/main/java/com/zjc/common/aop/WebLogAspect.java

计时必须包住 proceed(),如果用普通前置和后置通知,异常路径很容易漏掉失败耗时。

三、不要把请求对象序列化进日志

HttpServletRequestHttpServletResponseMultipartFile 被排除,只记录类型名。它们要么不适合 JSON 序列化,要么可能携带大文件和流对象。

返回值超过 2000 字符会截断,避免一个大列表把日志系统打出超高成本。

四、日志内容要有取舍

入参和出参日志在开发、测试环境很好用,生产环境要特别注意:

五、经验总结

AOP 解决的是“通用观测能力”,不是业务日志。关键业务动作仍应在 Service 层记录,例如订单创建成功、邮件发送失败原因。