java自定义异常通过隔离敏感字段、重写getmessage()、提供getsafelogmessage()等方法实现日志脱敏;结合logback/log4j2扩展、mdc结构化日志及spring aop切面,在日志输出前清洗敏感信息。

Java 中自定义异常本身不直接负责日志脱敏,但可以通过在异常构造、日志记录环节控制敏感信息的输出来实现脱敏打印。核心思路是:不让敏感数据进入异常消息体,或在日志输出前对异常信息做清洗。
在自定义异常中隔离敏感字段
不要把密码、手机号、身份证号等直接拼进 message。可将敏感数据作为独立字段存储,重写 toString() 或提供专用的日志方法,确保默认日志打印时不暴露。
- 定义私有敏感字段(如
private String idCard;),不参与super(message) - 重写
getMessage(),返回不含敏感内容的摘要信息(如"用户认证失败(ID: " + userId + ")") - 提供
getSafeLogMessage()方法,显式返回可用于日志的脱敏字符串(如"用户认证失败(ID: U***123)")
日志框架层统一拦截脱敏
借助 Logback 或 Log4j2 的 Converter 或 Layout 扩展能力,在日志格式化阶段自动过滤异常堆栈中的敏感词。
- Logback 示例:自定义
PatternLayout子类,在doLayout()中对event.getThrowableStrRep()做正则替换(如replaceAll("\d{17}[\dXx]", "***")) - Log4j2 示例:实现
LogEventPatternConverter,对异常信息字段进行预处理 - 避免全局暴力替换,建议结合上下文判断——仅对
Throwable相关字段脱敏,不影响业务日志正文
使用 MDC 配合结构化日志控制输出
将脱敏后的关键标识(如脱敏后的用户 ID、订单号)放入 MDC,再通过 JSON Layout 输出结构化日志,让敏感原始值彻底不进入日志文本流。
- 抛异常前:
MDC.put("userId", "U***890"); MDC.put("orderId", "ORD-2024-****5678"); - 配置 JSON Layout,只输出 MDC 中的键值,不打印异常
getMessage()全文 - 异常对象本身仍可保留完整信息用于调试(如本地开发环境),生产环境日志仅输出安全字段
配合 AOP 在日志切面中做异常后处理
用 Spring AOP 拦截异常日志行为,在真正调用 logger.error(...) 前,对 Throwable 进行标准化脱敏封装。
- 定义切点匹配所有
logger.error(Throwable)调用 - 在通知中判断异常类型,若为自定义敏感异常,调用其
toSafeString()替换日志内容 - 对非自定义异常(如
SQLException),提取 message 后做关键词模糊清洗(如移除 SQL 片段、URL 参数)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











