能构建稳定可维护的企业级全局异常拦截器,关键在于分层识别业务/框架/系统三类异常、统一响应结构并语义化http状态码、日志记录含traceid等上下文信息,且需规避二次抛异常、吞根因、优先级失控及异步异常遗漏等陷阱。

直接用 Spring Boot 的 @RestControllerAdvice + 自定义异常分类 + 统一响应模型,就能构建出稳定、可维护的企业级全局异常拦截器。关键不在“拦住所有异常”,而在“分层识别、精准响应、日志闭环”。
按异常类型分层拦截
不要只写一个 @ExceptionHandler(Exception.class) 兜底,否则所有错误都返回“系统内部错误”,前端无法区分是参数错、权限不足还是数据库挂了。应明确划分三类异常:
-
业务异常(如库存不足、订单已取消):继承
RuntimeException,带业务码(如ORDER_NOT_FOUND:1002),由服务层主动抛出; -
框架/校验异常(如
MethodArgumentNotValidException、ConstraintViolationException):捕获后提取字段级错误信息,返回具体提示(如“手机号格式不正确”); -
系统级异常(如
NullPointerException、SQLException):记录完整堆栈,对用户仅返回泛化提示(如“操作失败,请稍后重试”),避免暴露敏感细节。
统一响应结构 + 状态码语义化
前端依赖结构一致、状态码准确的响应。建议定义一个通用结果类(如 Result<t></t>),并严格绑定 HTTP 状态码:
- 400 Bad Request → 参数校验失败、请求体缺失;
- 401 Unauthorized → Token 过期或未携带;
- 403 Forbidden → 权限不足(如角色无操作权限);
- 404 Not Found → 资源不存在(非空指针,而是业务查不到);
- 500 Internal Server Error → 真正的未预期异常(兜底用,不暴露堆栈)。
例如处理参数校验异常时,不返回 500,而用 400 并附带各字段错误消息列表。
日志记录必须包含上下文
光打 logger.error("xxx", e) 不够。企业级要求每条异常日志至少含:
- 唯一 traceId(集成 Sleuth 或自动生成);
- 当前请求 URL、HTTP 方法、用户 ID(如有);
- 异常类型 + 精简消息(避免堆栈刷屏);
- 关键业务参数(脱敏后,如订单号、手机号前3后4)。
可在拦截器或 AOP 中提前注入 traceId 到 MDC,确保异常日志自动携带上下文。
避免常见设计陷阱
几个容易踩坑但影响深远的点:
-
不要在异常处理器里再抛异常:会导致二次崩溃,应确保所有
@ExceptionHandler方法 100% 安全退出; -
不要吞掉原始异常:封装为自定义异常时,务必用
super(message, cause)保留根因; -
不要让 @ControllerAdvice 生效范围失控:加
@Order(Ordered.HIGHEST_PRECEDENCE)确保优先级最高,避免被其他配置覆盖; -
不要忽略异步线程中的异常:@Async 方法抛出的异常不会被全局拦截器捕获,需单独处理或改用
CompletableFuture显式 handle。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











