异常冒泡是控制流设计原则而非语法糖,通过将拦截逻辑转为“放行-出错-向上归因”,精简拦截器至认证、租户注入、事务开启三类,字段校验下沉DTO层,日志等改用Filter/AOP,以语义化异常替代状态码路由,并在事务重试与全局异常处理中强化冒泡机制。

异常冒泡不是语法糖,而是控制流设计原则。在传统 ERP 系统中,大量动态拦截器(如权限校验、参数清洗、日志埋点、事务包装)层层嵌套,常导致调用栈深、响应延迟高、错误定位难。利用异常冒泡原语,可将“拦截-判断-转发”逻辑转为“放行-出错-向上归因”,大幅压缩拦截器数量与耦合度。
明确拦截器职责边界,只留关键断点
多数 ERP 拦截器实际承担两类任务:一类是必须阻断请求的强约束(如未登录、越权访问),另一类是可事后补救的弱干预(如字段格式微调、统计计数)。后者无需独立拦截器,应退化为业务方法内联检查或后置钩子。
- 保留且仅保留三类拦截器:认证拦截器、租户上下文注入器、全局事务开启器
- 将字段校验、空值处理、枚举转换等逻辑下沉至 DTO 绑定层或 Service 入口参数对象的构造函数中
- 日志、耗时、链路 ID 注入等非阻断行为,统一改用 EndpointFilter 或 AOP Around Advice,在异常冒泡后仍能执行
用异常类型代替状态码做路由决策
传统方式依赖 HTTP 状态码或返回枚举决定后续流程,易造成 if-else 泛滥;而基于异常类型的冒泡机制天然支持多级捕获,让框架自动分发到对应处理器。
- 定义语义化异常基类:BusinessException(业务拒绝)、ValidationException(参数不合法)、PermissionDeniedException(权限不足)、IntegrationTimeoutException(外部系统超时)
- 所有业务方法直接 throw 新建异常,不再 return Result
包装体 - 配置全局异常过滤器链,按异常类型优先级注册:PermissionDeniedExceptionFilter → ValidationExceptionFilter → BusinessExceptionFilter
在事务与重试边界处主动触发冒泡
ERP 中常见“先查再改”类操作,若并发写入冲突,传统做法是在 DAO 层 catch SQLException 后 retry,但重试逻辑分散、不可控。改为由业务层主动抛出 OptimisticLockException,并让外层拦截器统一识别、延时重试、限流降级。
- Service 方法中标注 @Retryable(on = OptimisticLockException.class, maxAttempts = 3)
- 拦截器捕获该异常后,不立即响应,而是记录重试上下文并重新 dispatch 请求
- 第三次失败时,冒泡至全局处理器,转为返回 409 Conflict + 业务友好提示
禁用静默吞异常的中间件,强制显式声明
很多 ERP 项目存在“兜底拦截器”——捕获所有异常后返回通用 500 页面,掩盖真实错误类型与堆栈。这直接破坏冒泡价值。应反向约束:任何拦截器若处理异常,必须满足其一:
- 处理后重新 throw 同一异常(确保上层可继续捕获)
- 包装为更高层语义异常(如将 SQLException → DataAccessException)并 throw
- 仅在最外层(如 ControllerAdvice)完成最终响应封装,其他层级禁止 writeOutput 或 setStatusCode










