Spring AOP记录接口日志的核心是通过@Aspect切面拦截Controller层public方法,精准定义切入点、安全序列化参数与响应、脱敏敏感字段,并控制日志粒度以保障性能。

在 Spring 项目中,用 AOP 记录接口访问日志,核心是通过切面(@Aspect)拦截控制器方法(如 @GetMapping、@PostMapping),在执行前后获取请求信息、参数、响应结果和耗时。关键在于精准定义切入点(Pointcut)、合理处理参数与异常,并避免敏感数据泄露。
定义切入点:只拦截 Controller 层的公开接口
使用 @Pointcut 匹配所有 @RestController 或 @Controller 中的 public 方法,推荐按注解匹配更清晰:
- 写法示例:
@Pointcut("@within(org.springframework.web.bind.annotation.RestController) || @within(org.springframework.web.bind.annotation.Controller)") - 再组合方法级注解(如
@GetMapping)可进一步缩小范围:@Pointcut("execution(* com.example..*Controller.*(..)) && @annotation(org.springframework.web.bind.annotation.RequestMapping) || @annotation(org.springframework.web.bind.annotation.GetMapping) || ...") - 实际开发中建议统一用包路径 + 注解方式,例如:
@Pointcut("execution(* com.example.web..*.*(..)) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")
记录请求基本信息:时间、URI、HTTP 方法、IP 和用户标识
在 @Before 增强中,从 RequestContextHolder 获取当前请求上下文:
- 用
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); - 提取
request.getRequestURL().toString()、request.getMethod()、request.getRemoteAddr() - 若已集成登录(如 Spring Security),可通过
SecurityContextHolder.getContext().getAuthentication().getName()获取当前用户名 - 注意:不要直接打印完整请求体(如 JSON body),避免日志污染或泄露密码等敏感字段
记录参数与响应:安全地序列化非敏感内容
用 @Around 拦截整个方法执行流程,捕获入参、返回值和异常:
立即学习“Java免费学习笔记(深入)”;
- 入参建议用
JSON.toJSONString(args, SerializerFeature.WriteMapNullValue)(FastJSON)或ObjectMapper.writeValueAsString()(Jackson)转为字符串,但先过滤掉含password、token、auth等字段的对象 - 响应结果可在
proceed()后获取,同样做脱敏处理;若返回值是ResponseEntity或自定义封装类(如Result<T>),需解析其 data 字段再记录 - 捕获异常时,记录
throwable.getMessage()即可,避免打印完整堆栈到业务日志(堆栈应进 error 日志文件)
控制日志粒度与性能:避免过度记录
AOP 日志容易成为性能瓶颈,尤其高频接口:
- 对 GET 查询类接口,可只记录 URI、参数摘要(如分页参数
page=1&size=20)、耗时和状态码 - 对 POST/PUT 接口,才记录入参摘要和返回摘要;大文件上传、流式响应等场景建议跳过参数记录
- 使用 SLF4J 的
isDebugEnabled()判断是否开启 debug 日志,避免无意义字符串拼接 - 考虑异步写日志(如 Logback 的 AsyncAppender),防止阻塞主线程
只要切点准确、参数脱敏到位、日志分级合理,Spring AOP 记录接口日志既轻量又实用,不需要额外引入链路追踪框架也能满足基础审计和问题排查需求。


















