首页 » java

RetryTemplate 详解:分布式系统中的“重试保险丝”

   发表于:java评论 (0)   热度:1

这里为您整理了 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)

重试策略决定了“在什么情况下需要重试”。常用的内置策略包括:

策略类

说明

SimpleRetryPolicy

最常用。默认重试所有异常,最多重试 3 次。可自定义最大次数及指定特定异常。

TimeoutRetryPolicy

在时间范围内进行重试,直到超时为止(默认超时时间为 1000ms)。

NeverRetryPolicy

从不重试,直接抛出异常。

AlwaysRetryPolicy

一直重试,直到成功(慎用,容易造成死循环)。

ExceptionClassifierRetryPolicy

基于异常分类器。可以对不同的异常配置不同的重试策略(例如:IO异常重试5次,业务异常不重试)。

CircuitBreakerRetryPolicy

集成了熔断器模式。当失败率达到阈值时,直接熔断,不再发起调用,过一段时间进入半开状态试探。

CompositeRetryPolicy

组合多个重试策略,满足所有条件(AND)或满足任一条件(OR)时触发重试。


四、 退避策略(BackOffPolicy)

退避策略决定了“重试前需要等待多久”,这是防止“重试风暴”压垮下游服务的关键。

策略类

说明

FixedBackOffPolicy

默认策略。每次重试间隔固定时间(默认 1000ms)。

ExponentialBackOffPolicy

最常用。指数级退避,间隔时间呈指数级增长(如 1s, 2s, 4s, 8s...),可设置初始值、乘数和最大值。

ExponentialRandomBackOffPolicy

在指数退避的基础上引入随机抖动(Jitter,通常随机增减 10%),防止多个客户端在同一时刻发起重试(共振效应)。

UniformRandomBackOffPolicy

在指定的最小值和最大值之间随机休眠。

NoBackOffPolicy

不等待,立刻发起下一次重试。


五、 监听器(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";
});

七、 版本变迁与注意事项

  1. Java 版本要求:Spring Retry 2.x 系列要求 Java 17​ 及以上环境。

  2. Micrometer 集成:自 2.0.8 版本起,提供了 MetricsRetryListener,可基于 Micrometer 将重试次数、耗时等指标上报至 Prometheus 等监控系统。

  3. 虚拟线程支持:为了适配 Java 21+ 的虚拟线程,引入了 RetrySynchronizationManager.setUseThreadLocal(false)以避免 ThreadLocal带来的内存泄漏和语义问题。

通过以上模块的灵活组合,Spring Retry 能够为企业的关键业务链路提供 robust(健壮)且可控的防故障扩散能力。

(。・v・。)
喜欢这篇文章吗?欢迎分享到你的微博、QQ群,并关注我们的微博,谢谢支持。