
Spring Retry 支持通过 @Recover 方法为不同异常类型提供定制化恢复逻辑,结合 @Retryable 的精准异常过滤,可实现“仅对特定异常重试、对另一些异常直接返回默认值、对其他异常透传抛出”的灵活容错策略。
spring retry 支持通过 `@recover` 方法为不同异常类型提供定制化恢复逻辑,结合 `@retryable` 的精准异常过滤,可实现“仅对特定异常重试、对另一些异常直接返回默认值、对其他异常透传抛出”的灵活容错策略。
在实际微服务调用或外部依赖集成场景中,我们常需区分三类错误行为:
- ✅ 可重试的瞬时故障(如网络超时、限流拒绝)→ 应自动重试;
- ⚠️ 业务可兜底的非重试异常(如下游返回特定错误码)→ 不重试,但需返回预设默认值(如
7); - ❌ 不可恢复的致命异常(如参数校验失败、数据一致性破坏)→ 立即终止并原样抛出。
Spring Retry 原生不支持在 RetryListener.onError() 中修改返回值,也无法在 RetryPolicy 中将异常“转换”为成功结果——但这并不意味着无法实现题设中的 analyze_thrown_exception() 语义。关键在于:将异常分类逻辑前置到业务方法体内,再配合多态 @Recover 方法完成差异化恢复。
✅ 正确实践:异常分类 + 类型化恢复
首先,定义语义明确的自定义异常:
public class RetryableException extends RuntimeException {
public RetryableException(String message) { super(message); }
}
public class BusinessFallbackException extends RuntimeException {
public BusinessFallbackException(String message) { super(message); }
}
然后,在 @Retryable 方法中主动捕获并分类异常,不依赖框架自动匹配,而是由你掌控何时抛出何种异常:
@Service
@Slf4j
public class MyRetryableService {
@Retryable(
value = {RetryableException.class}, // 仅对此类异常重试
maxAttempts = 3,
backoff = @Backoff(delay = 100, multiplier = 2)
)
public int do_something_that_may_throw_exception() {
try {
// 模拟真实调用
return performExternalCall();
} catch (Exception e) {
int analysis = analyze(e);
switch (analysis) {
case 1:
log.info("Business condition met → return default value 7 immediately");
return 7; // ✅ 不抛异常,直接返回成功结果
case 2:
log.warn("Transient failure → retry with RetryableException");
throw new RetryableException("Transient error: " + e.getMessage());
default:
log.error("Permanent failure → throw non-retryable exception");
throw new BusinessFallbackException("Permanent error: " + e.getMessage());
}
}
}
private int analyze(Exception e) {
// 实际中可基于异常类型、消息、HTTP 状态码等深度判断
if (e instanceof SocketTimeoutException || e.getMessage().contains("timeout")) {
return 2; // transient
} else if (e instanceof IllegalArgumentException && e.getMessage().contains("invalid id")) {
return 1; // fallback
}
return -1; // permanent
}
private int performExternalCall() {
// 模拟不稳定的外部调用
if (Math.random() <h3>⚠️ 注意事项与最佳实践</h3>
-
@Recover方法签名必须匹配:参数列表需包含对应异常类型 + 原方法所有入参(若原方法有参数),返回类型必须与原方法一致; -
恢复方法优先级由异常继承关系决定:更具体的子类异常会优先匹配其
@Recover方法; -
不要在
@Retryable方法中吞掉所有异常:若统一catch(Exception)后无差别throw new RuntimeException(),则失去分类能力; -
启用 Spring Retry 功能需添加依赖与配置:
<!-- Maven --> <dependency><groupid>org.springframework.retry</groupid><artifactid>spring-retry</artifactid></dependency><dependency><groupid>org.springframework.boot</groupid><artifactid>spring-boot-starter-aop</artifactid></dependency>
并在主类或配置类上添加
@EnableRetry; -
生产建议:将
analyze()逻辑封装为独立策略组件,支持 SPI 扩展,便于后续对接熔断、降级中心(如 Sentinel)。
通过这种“方法内异常路由 + 类型化恢复”模式,你完全可以在 Spring Retry 框架约束下,精准实现题设中 case 1/2/default 的三段式容错语义——既保持代码清晰性,又不牺牲框架的重试生命周期管理能力。










