AOP切面统一记录公共方法入参出参的核心是精准切入、安全序列化与上下文补全。推荐按自定义注解或包+层结构切入,排除敏感类型;入参需脱敏、结构化并补充HTTP上下文;出参与异常应分路径处理,@Around适用于统一错误响应转换。

用 AOP 切面统一记录公共方法的入参和出参,核心是不侵入业务代码、可控可配置、兼顾安全与性能。关键不在“全量拦截”,而在“精准切入 + 安全序列化 + 上下文补全”。
选对切点方式,避免误打和性能损耗
全包扫描(如 execution(* com.example..*.*(..)))容易命中工具类、DTO构造器、JSON反序列化方法等非业务逻辑,既产生无效日志,又拖慢响应。推荐两种务实方案:
- 按自定义注解切入:定义如
@LogArgs或@Trace,仅在 Controller 层或 Service 关键方法上显式标注,语义清晰、粒度可控 - 按包+层结构切入:例如
execution(* com.example.controller..*.*(..))或结合@within(@Controller),适合需要全量记录接口层请求的场景 - 务必排除敏感/不可序列化类型:如含
MultipartFile、InputStream、OutputStream参数的方法,跳过日志,防止 Jackson/Gson 序列化失败导致接口异常
入参记录要脱敏、带上下文、结构化输出
@Before 是获取入参最稳妥的时机。注意三点:参数获取、字段脱敏、上下文增强。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用
joinPoint.getArgs()获取参数数组,优先选用 Jackson 或 Gson 序列化(避免 Fastjson 在上传接口中引发兼容问题) - 手机号、身份证、邮箱、密码等字段必须脱敏:手机号转为
138****1234,身份证保留前后 4 位,密码字段直接替换为[REDACTED] - 补充必要上下文:从
RequestContextHolder提取 HTTP 方法、URL、客户端 IP;从 MDC 或 ThreadLocal 中提取traceId,便于链路追踪 - 日志格式建议统一为 JSON 结构或带标签的文本,例如:
[INFO] POST /api/order/create, IP: 10.0.1.5, traceId: xyz789, args: {"userId":1001,"amount":99.9,"cardNo":"6228****1234"}
出参和异常需分路径处理,各司其职
返回值和异常不能混在同一通知里处理——它们触发时机不同、关注重点不同。
立即学习“Java免费学习笔记(深入)”;
- 出参用
@AfterReturning(returning = "ret")拦截:只在方法成功返回后执行,适合记录正常响应体。若返回值过大(如文件流、大数据集合),建议默认关闭或加开关控制(如注解中saveResult = false) - 异常用
@AfterThrowing(throwing = "e")捕获:必须显式声明throwing属性并接收Throwable e,否则拿不到异常实例;提取e.getClass().getSimpleName()、e.getMessage()和关键堆栈行(建议截前 5 行),避免日志刷屏 - 不要在
@AfterReturning里尝试捕获异常——它根本收不到;也不要让@AfterThrowing干返回值的事——它压根没返回值
进阶:用 @Around 统一兜底,兼顾日志与响应转换
如果还需将异常统一包装成标准响应(如 { "code": 500, "msg": "系统繁忙" }),单靠前置/后置通知不够,得用 @Around。
- 包裹
proceed()执行,在 catch 块中完成三件事:记录异常日志、构造统一错误响应、返回该响应体 - 注意区分“记录日志”和“影响流程”:日志是观察行为,而响应转换是干预行为,二者逻辑分离更易维护
- 若仅需日志,
@Before + @AfterReturning + @AfterThrowing组合已足够轻量;若需统一错误处理,再叠加@Around即可

















