Spring Retry 异常重试机制:从入门到生产实践

Spring Retry 异常重试机制:从入门到生产实践

适用版本:Spring Boot 3.x + spring-retry 2.x
本文覆盖 注解声明式RetryTemplate 编程式监听器最佳实践避坑清单,可直接落地生产。


一、核心坐标


<dependency>
    <groupId>org.springframework.retrygroupId>
    <artifactId>spring-retryartifactId>
dependency>

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-aopartifactId>
dependency>

二、开启重试能力

在启动类或任意 @Configuration 上添加:

@SpringBootApplication
@EnableRetry        // <-- 只需这一行
public class Application { }

三、注解式:最常用 80% 场景

3.1 基本用法

@Service
public class OrderService {

    @Retryable(
        retryFor = ConnectException.class,   // 触发重试的异常
        maxAttempts = 3,                     // 含首次,共 3 次
        backoff = @Backoff(
            delay = 1000,                    // 首次延迟 1s
            multiplier = 1.5                // 指数退避 1→1.5→2.25s
        )
    )
    public void pay(int orderId) throws ConnectException {
        // 模拟远程调用
        throw new ConnectException("网络抖动");
    }
}

3.2 兜底恢复

@Recover
public void payRecover(ConnectException e, int orderId) {
    log.error("订单 {} 支付失败,进入补偿流程", orderId);
    // 发消息、记录表、人工审核...
}

注意@Recover 方法签名必须与 @Retryable 一致(异常类型 + 参数 + 返回值),否则不生效 。


四、编程式:RetryTemplate 细粒度控制

适用于 动态策略无 Spring Bean 场景

@Configuration
public class RetryConfig {

    @Bean
    public RetryTemplate retryTemplate() {
        return RetryTemplate.builder()
                .maxAttempts(5)
                .exponentialBackoff(1000, 1.5, 10000) // 初始 1s、乘 1.5、最大 10s
                .retryOn(ConnectException.class)
                .build();
    }
}

@Service
public class ReportService {

    @Autowired
    private RetryTemplate retryTemplate;

    public String generate() {
        return retryTemplate.execute(ctx -> {
            // 模板内部自动重试
            return remoteClient.generate();
        });
    }
}

五、监听重试生命周期

实现 RetryListener 可以 记录指标 / 报警 / 链路追踪

@Component
public class RetryLogger implements RetryListener {

    @Override
    public <T, E extends Throwable> void onError(RetryContext ctx,
                                                 RetryCallback<T, E> callback,
                                                 Throwable throwable) {
        log.warn("第 {} 次重试失败: {}", ctx.getRetryCount(), throwable.getMessage());
    }
}

注册到模板:

retryTemplate.registerListener(new RetryLogger());

六、生产级最佳实践

维度 建议
重试场景 仅对 网络、锁、瞬时故障;业务校验失败不重试
次数 & 退避 3~5 次 + 指数退避,避免雪崩
幂等性 写操作需保证 幂等键 / 去重表
超时控制 方法级别设置 timeout,防止长时间阻塞
监控告警 通过 Micrometer + RetryListener 导出 重试次数、成功率

七、常见踩坑清单

症状 原因 解决
重试不触发 直接 new 调用 / 异常被吃掉 必须走 Spring 代理抛出异常
@Recover 不执行 签名不一致 保持异常类型、参数、返回值一致
无限重试 maxAttempts = Integer.MAX_VALUE 显式设置合理上限
线程阻塞 退避策略未设 maxDelay 设置最大等待时间

八、小结一句话

Spring Retry 通过 注解 + AOPRetryTemplate 提供声明式/编程式重试,在 可观测、可配置、无侵入 的前提下极大提升了分布式系统的健壮性;
牢记“次数、退避、幂等、监控”四要素,即可安全落地生产。

完整示例代码已上传 GitHub:
https://github.com/your-org/spring-retry-demo

你可能感兴趣的:(SpringBoot,高效的Java开发实践,spring,数据库,java,spring,boot)