spring aop统一拦截controller方法结合fastjson序列化,需精准控制日志粒度(自定义注解或包路径切点+redis动态开关),参数与返回值结构化序列化并脱敏,日志包含路径、ip、用户id、耗时、状态码及异常,异步落库并分级输出。

用 Spring AOP 统一拦截 Controller 方法,结合 FastJSON 序列化参数与返回值,是最常用且低侵入的方式。关键不是“能不能记”,而是“记哪些、怎么记得清、怎么不影响性能”。
只对需要的接口记录,避免全量日志爆炸
盲目拦截所有 Controller 会导致日志量激增,尤其在高并发或含大文件上传的接口中。推荐两种控制粒度的方式:
- 用自定义注解(如 @LogRequest)标注具体方法,精准开启日志;
- 或按包路径切点(如 execution(* com.example.api..*Controller.*(..))),限定在对外暴露的 API 层;
- 配合 Redis 动态开关(如 key = log:enabled:paths),运行时启停某类接口日志,无需重启服务。
参数和返回值要可读、可还原
直接打印对象引用(如 toString())没意义,必须序列化成结构化文本:
- 请求参数:从 HttpServletRequest 取 query/body 参数,用 FastJSON.toJSONString(params, SerializerFeature.WriteMapNullValue) 保留空字段;
- 响应数据:若返回 ResponseEntity> 或自定义 Result 包装类,需反射提取 body 内容再序列化;
- 敏感字段(如密码、身份证号)建议在序列化前脱敏,例如通过 JSONWriter 自定义 ValueFilter。
日志内容至少包含 5 个核心字段
光有参数和返回值不够,排查问题时还需上下文信息:
- 请求路径(requestURI)+ HTTP 方法(GET/POST);
- 客户端 IP(注意代理场景下要用 X-Forwarded-For 多级解析);
- 登录用户 ID(从 Token 或 Session 中提取,非 request.getParameter);
- 执行耗时(毫秒级,用 ThreadLocal 记录开始时间,@AfterReturning 中计算差值);
- 状态码与异常堆栈(@AfterThrowing 捕获异常并记录完整 stackTrace)。
异步落库 + 日志分级,兼顾可查性与性能
同步写数据库会拖慢接口响应,尤其当日志表无索引或磁盘 I/O 紧张时:
- 日志实体(如 RequestLog)先存入内存队列,由独立线程池异步刷入 MySQL 或写入 Elasticsearch;
- 同时保留一份轻量级文本日志(如 logback 输出到 access.log),仅含 path、ip、status、duration,便于快速 grep;
- 调试阶段用 DEBUG 级别输出完整出入参,生产环境调为 INFO,异常强制 ERROR 级别并告警。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











