自定义异常是触发降级与补偿的信号开关,需按语义区分受检/非受检/带元数据类型,构造时注入上下文,结合Spring声明式注解实现自动降级、重试与异步补偿,并全链路可观测。

自定义异常本身不直接实现降级或补偿,但它可以成为触发降级与补偿逻辑的“信号开关”。关键在于:把异常作为上下文载体,结合策略分发、责任分离和可配置行为,让系统在抛出异常后能自动走向合理回退路径。
用异常类型明确降级意图
不同异常应携带不同的业务语义,而不是统一 throw new Exception("xxx"):
- 受检异常(如 ServiceUnavailableException):表示外部依赖不可用,适合触发熔断+fallback,调用方必须显式处理
- 非受检异常(如 ValidationException、RateLimitExceededException):属于参数或流程问题,适合快速失败+返回友好提示,不强制上层重试
- 带元数据的异常(如 TimeoutExceptionWithTraceId extends TimeoutException):封装 traceId、服务名、超时阈值等,便于日志追踪与补偿任务关联
异常链中注入补偿线索
不要只包装异常,要让它“带话”给后续处理器:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 在构造自定义异常时,传入原始请求参数、唯一任务ID、重试次数上限等上下文
- 例如:
throw new PaymentTimeoutException(orderId, "pay-service", 3, cause); - 捕获该异常的兜底模块(如全局异常处理器或FallbackFactory)可据此决定:是否重试、是否写入延迟队列、是否调用本地 mock 方法
配合 Spring 生态实现声明式降级
借助 Spring 的扩展点,让异常自动导向补偿动作,避免满屏 try-catch:
立即学习“Java免费学习笔记(深入)”;
- 用
@ExceptionHandler拦截特定自定义异常,统一返回降级响应(如默认库存、缓存兜底值) - 在 FeignClient 上用
@FeignFallback注解,由自定义FallbackFactory根据异常类型动态选择补偿逻辑(如网络异常走本地计算,限流异常返回空列表) - 结合
@Retryable和@Recover,对可重试异常(如 TransientNetworkException)做指数退避重试;失败后进入 recover 方法执行补偿(如发告警、记补偿日志、调用异步修复服务)
为异常设计可观察、可补偿的生命周期
一次异常发生不是终点,而是补偿流程的起点:
- 所有自定义异常被抛出前,记录结构化日志(含异常码、traceId、业务ID、堆栈摘要),避免日志淹没
- 在全局异常拦截器中判断:若异常属于需补偿类(如支付超时、消息发送失败),则异步提交一条补偿任务到可靠队列(如 RocketMQ 事务消息 或 DB 补偿表)
- 补偿任务包含完整上下文快照(非实时对象引用),确保执行时数据一致
- 提供管理端口(如 Actuator endpoint)查询待补偿任务数、失败原因分布、平均补偿耗时,支撑容量评估

















