Spring Boot全局异常重构需分层设计:统一响应结构(含泛型、时间戳、业务码枚举)、按场景定义Client/Business/System异常、分层捕获处理、日志集成traceId与关键上下文。

Spring Boot 全局异常代码重构不是换个注解就完事,关键在于建立分层清晰、职责明确、可扩展的异常处理契约。核心是把“哪里出错”“错成什么样”“怎么告诉用户”“怎么记日志”四件事拆开管,而不是堆在 try-catch 里一锅炖。
统一响应结构是前提
所有接口(无论成功或失败)必须返回同一套字段结构,前端才不用写多套解析逻辑。推荐使用带泛型、时间戳和业务码枚举的 Result 类:
- code 字段不硬编码数字,而是引用枚举(如 ResultCode.ORDER_NOT_FOUND),避免散落的 404、601、702 等魔法值;
- message 字段只返回用户可读提示,禁止拼接堆栈或 SQL 语句;
- data 字段在异常时强制为 null,避免前端误用残留数据;
- 增加 timestamp 字段,方便前后端排查时序问题。
自定义异常要按场景建模
别只写一个 BusinessException,应按错误性质分层定义:
- ClientException(4xx 类):参数校验失败、Token 过期、请求方法不支持——这类错误前端可重试或修正后重发;
- BusinessException(6xx 类):库存不足、订单已取消、权限不足——属于业务规则拦截,需明确业务码与提示;
- SystemException(5xx 类):数据库连接超时、远程服务不可达——应自动触发告警,响应中隐藏细节,只返回“系统繁忙”;
- 所有自定义异常都继承 RuntimeException,不强制上层 try-catch,保持调用链干净。
@RestControllerAdvice 要分层捕获
一个全局处理器类里不要塞十几个 @ExceptionHandler 方法。按异常类型分组、按处理策略隔离:
- 专门捕获 ClientException → 返回 400 + 友好提示,不打 ERROR 日志,只 WARN;
- 专门捕获 BusinessException → 返回对应业务码(如 601),记录 WARN 日志并带上关键上下文(如 orderId、userId);
- 兜底捕获 Exception → 返回 500,打 ERROR 日志并保留完整堆栈,同时异步推送告警;
- 显式排除 NullPointerException、IllegalArgumentException 等低级异常,让它们走兜底逻辑,倒逼开发阶段暴露问题。
日志与监控要联动设计
异常日志不是为了“有记录”,而是为了“能定位”。每条异常日志必须包含:
- 唯一 traceId(通过 MDC 注入,贯穿整个请求);
- 当前接口路径、HTTP 方法、用户 ID(如有);
- 关键业务参数快照(如 id=123, status="PENDING"),避免日志里只有“空指针”却找不到上下文;
- 对 BusinessException 级别异常,禁用堆栈输出,防止刷屏;对系统级异常,堆栈必须完整且异步落盘。
不复杂但容易忽略:重构不是一次动作,而是把异常当作接口契约的一部分来维护——新增一个业务规则,就要同步更新对应异常枚举、提示文案、日志字段和告警阈值。


















