异常处理需嵌入分层架构:接入层拦截非法输入并返回标准http码;服务层聚焦业务规则,定义明确业务异常;数据层封装技术细节,统一转换dao异常;全局处理器统一响应、兜底审计。

异常处理不是加个 try-catch 就完事,它必须嵌入系统分层架构的设计逻辑中——每层只处理自己该管的异常,不该越界,也不该静默吞掉。
接入层:拦截非法输入与协议级错误
这是用户请求进入系统的第一个关口。重点不是捕获业务异常,而是识别并拒绝明显无效或危险的请求,比如参数缺失、JSON 格式错误、超长字段、非法字符、未授权访问等。这类异常应快速响应,返回清晰的 HTTP 状态码(如 400、401、403)和简明提示,不暴露内部细节。
- 用统一的参数校验框架(如 Spring Validation)前置拦截,避免脏数据流入下层
- 对反序列化失败(如 JSON 解析异常)直接返回 400,不抛到服务层
- 网关层可统一处理跨域、限流、鉴权失败等,保持业务服务轻量
服务层:聚焦业务规则与领域一致性
这一层承载核心逻辑,异常应反映真实业务约束。例如“余额不足”“库存已售罄”“订单状态不可变更”,这些不是程序 bug,而是合法的业务分支。推荐定义明确的业务异常类(如 InsufficientBalanceException),由上层(接入层)转化为用户友好的提示。
- 避免用 RuntimeException 泛化所有业务异常,区分 checked 与 unchecked 的语义
- 事务边界内发生的异常需确保回滚干净,尤其涉及多资源更新时
- 不在此层记录敏感信息(如完整堆栈、用户密码),日志级别设为 WARN 或 ERROR 即可
数据访问层:封装技术细节,屏蔽底层差异
数据库连接超时、主键冲突、唯一索引失败、SQL 语法错误等,都属于基础设施问题。这一层应将原始 JDBC 异常、MyBatis 报错、Redis 连接异常等,统一转换为更抽象、稳定的 DAO 异常(如 DataAccessException),向上只暴露“查不到”“保存失败”等语义,不泄露 MySQL 或 Redis 的具体错误码。
- 用 Spring 的 @Repository 注解自动将底层异常转为 DataAccessException 体系
- 对主键/唯一约束冲突,可封装为 DuplicateKeyException,供服务层判断是否重试或提示用户重试
- 连接池耗尽、网络中断等瞬态故障,建议配合重试机制(如 @Retryable),而非直接向上抛出
全局异常处理器:统一响应格式与分级兜底
各层抛出的异常最终由一个中心化处理器(如 Spring 的 @ControllerAdvice)收口。它的作用不是替代分层处理,而是兜底、归一、审计:把不同类型的异常映射成标准响应体,记录关键日志,触发告警(如严重异常),并防止未捕获异常导致服务崩溃。
- 按异常类型匹配处理逻辑,业务异常返回 200 + code 字段,系统异常返回 500
- 对未知异常(Throwable)做最小化响应(如“系统繁忙”),同时记录完整堆栈到独立错误日志
- 避免在全局处理器里执行复杂业务逻辑(如发短信、调第三方),保持轻量和可预测
分层异常处理的本质是职责分离——谁的问题谁负责,谁的边界谁守住。漏一层,就可能让一个数据库超时变成前端的“未知错误”,也可能让一次用户输错密码触发整条链路的告警风暴。











