RetryTemplate 详解:分布式系统中的“重试保险丝”
这里为您整理了 org.springframework.retry(Spring Retry)的详细参考文档。它是 Spring 生态中用于处理声明式与命令式重试的核心模块,广泛用于 Spring Batch、Spring Integration 以及微服务通信中。
Spring Retry 官方文档精析
以下文档结合 实战场景示例 查看
一、 项目简介与状态
Spring Retry 为 Spring 应用程序提供了自动重试失败操作的能力。这对于处理瞬时错误(如网络波动、数据库连接闪断、服务短暂不可用等)尤为有效。
⚠️ 项目状态提醒:根据官方仓库通告,Spring Retry 已进入 Maintenance(维护)模式,不再接受新功能(Enhancements)。其功能部分已被 Spring Framework 7 及响应式生态取代,但在传统的同步阻塞(Servlet)栈中依然是事实上的重试标准。
二、 核心 API 与架构
Spring Retry 的设计高度模块化,其核心分为重试策略、退避策略和执行上下文。
1. 顶层执行入口:RetryOperations
定义了重试执行的基本契约,是所有重试模板的顶层接口。
public interface RetryOperations {
<T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback) throws E;
<T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback, RecoveryCallback<T> recoveryCallback) throws E;
// ... 支持有状态重试的重载方法
}
2. 具体执行器:RetryTemplate
RetryOperations的默认实现类。通过组合不同的策略(Policy)来控制重试行为。自 1.3 版本起,支持使用 Builder 模式流式构建。
RetryTemplate template = RetryTemplate.builder()
.maxAttempts(3)
.exponentialBackoff(100, 2, 10000)
.retryOn(IOException.class)
.build();
3. 业务逻辑载体:RetryCallback
用户需要把真正执行的业务逻辑(即可能发生失败并需要重试的代码)包装在这个接口的 doWithRetry方法中。
public interface RetryCallback<T, E extends Throwable> {
T doWithRetry(RetryContext context) throws E;
}
4. 兜底恢复:RecoveryCallback
当重试次数耗尽依然失败时,如果提供了该接口的实现,则会转而执行此方法,返回一个兜底的默认值或进行降级处理,避免异常抛出。
5. 重试上下文:RetryContext
在重试生命周期中传递的上下文对象。可用于存储迭代过程中的数据(Attribute Bag)。可通过 RetrySynchronizationManager.getContext()获取当前线程的重试上下文。自 Java 21 虚拟线程(Virtual Threads)兴起后,建议调用 RetrySynchronizationManager.setUseThreadLocal(false)将其改为基于 Map 的存储。
三、 重试策略(RetryPolicy)
重试策略决定了“在什么情况下需要重试”。常用的内置策略包括:
|
策略类 |
说明 |
|---|---|
|
|
最常用。默认重试所有异常,最多重试 3 次。可自定义最大次数及指定特定异常。 |
|
|
在时间范围内进行重试,直到超时为止(默认超时时间为 1000ms)。 |
|
|
从不重试,直接抛出异常。 |
|
|
一直重试,直到成功(慎用,容易造成死循环)。 |
|
|
基于异常分类器。可以对不同的异常配置不同的重试策略(例如:IO异常重试5次,业务异常不重试)。 |
|
|
集成了熔断器模式。当失败率达到阈值时,直接熔断,不再发起调用,过一段时间进入半开状态试探。 |
|
|
组合多个重试策略,满足所有条件(AND)或满足任一条件(OR)时触发重试。 |
四、 退避策略(BackOffPolicy)
退避策略决定了“重试前需要等待多久”,这是防止“重试风暴”压垮下游服务的关键。
|
策略类 |
说明 |
|---|---|
|
|
默认策略。每次重试间隔固定时间(默认 1000ms)。 |
|
|
最常用。指数级退避,间隔时间呈指数级增长(如 1s, 2s, 4s, 8s...),可设置初始值、乘数和最大值。 |
|
|
在指数退避的基础上引入随机抖动(Jitter,通常随机增减 10%),防止多个客户端在同一时刻发起重试(共振效应)。 |
|
|
在指定的最小值和最大值之间随机休眠。 |
|
|
不等待,立刻发起下一次重试。 |
五、 监听器(RetryListener)
允许在重试的生命周期中插入自定义的横切逻辑(如日志记录、监控埋点)。
public interface RetryListener {
default <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { return true; }
default <T, E extends Throwable> void onSuccess(RetryContext context, RetryCallback<T, E> callback, T result) { }
default <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { }
default <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { }
}
注:自 2.0 版本起,新增了 onSuccess回调,允许在每次成功调用后检查返回结果是否符合预期,若不符合可手动触发重试。
六、 使用指南
1. 声明式使用(基于注解,推荐)
步骤一:引入依赖(以 Maven 为例)
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<!-- 声明式重试依赖 AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
步骤二:开启重试功能
在 Spring Boot 主类或配置类上添加 @EnableRetry。
@SpringBootApplication
@EnableRetry
public class Application { ... }
步骤三:在需要重试的方法上使用 @Retryable和 @Recover
@Service
public class PaymentService {
// 当抛出 RemoteAccessException 时,最多重试 3 次(含首次)
@Retryable(retryFor = RemoteAccessException.class, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2))
public String callRemoteApi() {
// 可能会失败的业务逻辑
return restTemplate.getForObject("...", String.class);
}
// 兜底方法:方法签名需与原方法一致(或首参数为 Throwable),返回值需兼容
@Recover
public String recover(RemoteAccessException e) {
return "降级数据";
}
}
2. 命令式使用(基于 Template)
适合在非 Spring Bean 中、或者需要高度动态定制重试逻辑的场景下使用。
RetryTemplate template = RetryTemplate.builder()
.maxAttempts(5)
.fixedBackoff(500)
.retryOn(SQLException.class)
.build();
String result = template.execute(ctx -> {
// 这里的代码会在每次重试时执行
return database.queryData();
}, ctx -> {
// 重试耗尽后的兜底逻辑
return "default";
});
七、 版本变迁与注意事项
-
Java 版本要求:Spring Retry 2.x 系列要求 Java 17 及以上环境。
-
Micrometer 集成:自 2.0.8 版本起,提供了
MetricsRetryListener,可基于 Micrometer 将重试次数、耗时等指标上报至 Prometheus 等监控系统。 -
虚拟线程支持:为了适配 Java 21+ 的虚拟线程,引入了
RetrySynchronizationManager.setUseThreadLocal(false)以避免ThreadLocal带来的内存泄漏和语义问题。
通过以上模块的灵活组合,Spring Retry 能够为企业的关键业务链路提供 robust(健壮)且可控的防故障扩散能力。
(。・v・。)