大型系统中自定义异常是业务语义分层、错误治理、可观测性与协作契约的关键载体,需通过三层继承结构、结构化错误码、上下文注入、全局处理器实现可读、可路由、可追溯、可响应。

大型系统中,自定义异常不是“多写几个类”那么简单,而是业务语义分层、错误治理、可观测性与协作契约的关键载体。核心目标是让异常成为可读、可路由、可追溯、可响应的业务信号,而非掩盖问题的黑盒。
统一基类与分层设计
避免零散定义,建立三层继承结构:
-
顶层业务异常基类(如
BaseBusinessException):继承RuntimeException,统一携带errorCode、errorMessage、timestamp、traceId字段,支持序列化与日志上下文注入 -
领域级子类(如
AccountException、OrderException、PaymentException):按限界上下文划分,体现业务边界,便于模块隔离与团队自治 -
场景级具体异常(如
InsufficientBalanceException、InvalidPromotionCodeException):精准描述失败原因,命名动宾结构、不含模糊词(如 “Error”、“Failed”),直接映射业务规则
错误码体系必须结构化
错误码不是字符串拼接,而是可解析、可管理的元数据:
- 采用固定格式,例如
ACC-001(领域前缀 + 类型 + 序号),支持快速定位模块与错误类型 - 配套维护
error-code.yaml或数据库表,记录每个码对应的中文提示、HTTP状态码、是否可重试、前端展示策略 - 禁止在代码中硬编码错误码字符串;通过枚举或常量类统一管理,确保编译期校验与 IDE 提示
异常构造与传播规范
异常实例应自带上下文,杜绝“裸抛”:
立即学习“Java免费学习笔记(深入)”;
- 所有构造函数必须支持传入原始异常(
cause),保留异常链,便于根因分析 - 关键业务参数(如订单ID、用户ID、金额)应作为构造参数注入,自动写入异常消息和 MDC 日志上下文
- 禁止在 service 层 catch 后“吞掉再抛新异常”——除非明确需要转换语义;否则应原样向上抛出,由统一异常处理器拦截
与框架协同的全局处理机制
脱离 Spring @ControllerAdvice 或 WebFlux 的全局异常处理器,自定义异常就失去价值:
- 统一返回体封装:对所有
BaseBusinessException子类,返回标准 JSON 格式(含 code、message、path、timestamp),HTTP 状态码按错误性质映射(如参数类用 400,权限类用 403,系统类用 500) - 敏感信息过滤:异常消息中自动脱敏用户手机号、身份证、银行卡等字段,防止日志/响应泄露
- 分级告警:根据错误码前缀或异常类型,对接监控系统(如 Prometheus + AlertManager),对高频
ORDER-005(库存超卖)触发即时告警,对低频PAY-012(渠道回调签名失败)仅记录审计日志


















