Spring Retry实现优雅的重试


1. 基本介绍

在业务常见开发中经常我们会涉及到失败重试的逻辑,如当发送通知失败后再次尝试。

针对此类场景最简单粗暴的方式即 CV 大法,但显然这种方式不够优雅,为此 Spring Boot 中提供了 Retry 从而实现优雅的异常失败重试。

2. 依赖导入

在开始前在 Spring Boot 工程中引入相应的 Retry 依赖。

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

3. 异常处理

Spring Retry 的使用也及其简单,通过 @Retryable 注解配置,其基本配置参考下表。

参数 描述
value 配置何种情况重试。
include 配置触发重试情况的异常类型。
exclude 配置不触发重试情况的异常类型。
maxAttempts 通过配置尝试次数,默认为 3。
maxAttemptsExpression 通过表达式配置尝试次数,默认为 3。
backoff 通过表达式配置间隔时间。
recover 指定重试后仍失败触发的方法。

如下述示例代码中则设置当 call() 方法抛出 RuntimeException 异常时重试两次,每次重试间隔 500 毫秒。

@Component
public class RetryService {

    @Retryable(
            value = RuntimeException.class,
            // 设置尝试次数,默认为 3
            maxAttempts = 2,
            // maxAttemptsExpression = "${retry.maxAttempts}",
            // 设置每次尝试间隔时间,默认 1 秒,此处设为 500 毫秒
            backoff = @Backoff(delay = 500)
            // 通过表达式配置间隔时间
            // backoff = @Backoff(delayExpression = "${retry.maxDelay}")
    )
    public void call(boolean failed) {
        if (failed) {
            System.out.println("================ >>> retry.");
            throw new RuntimeException();
        }
    }
}

4. 恢复事件

重试的恢复事件由 @Recover 注解控制,即当 @Retryable 方法达到重试次数仍失败时触发。

需要注意的是 @Recover 注解的标注的方法第一个参数必须与 @Retryable 中的 value 类型一致,剩余参数则必须与 @Retryable 修饰的方法入参一致。

@Component
public class RetryService {

    /**
     * "@Retryable" 重试指定次数后若仍失败则触发 "@Recover"
     * <p>
     * 第一个方法参数为 "@Retryable" 中监听的异常类型
     * 第二个方法参数为 "@Retryable" 方法中剩余的入参
     */
    @Recover
    public void recover(RuntimeException e, boolean failed) {
        System.out.println("================ >>> recover, params: " + failed);
    }
}

新建测试类 RetryController 调用接口后即可看到控制台分别打印了两句 >>> retry 与一句 >>> recover 日志信息,说明重试机制生效了。

@RestController
@RequestMapping("/api/retry")
public class RetryController {

    @Autowired
    private RetryService retryService;

    @GetMapping("demo1")
    public void demo(boolean failed) {
        retryService.call(failed);
    }
}

5. 配置管理

除了在方法上通过 @Retryable 注解显式设置尝试策略,也可通过全局的配置修改默认的尝试次数与间隔时间等信息。

新建配置类 AppConfig,具体的配置内容参考下述示例,此处的配置将全局生效,当然仍可在方法处通过 @Retryable 注解覆盖配置。

@EnableRetry
@Configuration
public class AppConfig {

    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        // Set retry policy
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(1);
        retryTemplate.setRetryPolicy(retryPolicy);
        // Set interval policy
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(2000l);
        retryTemplate.setBackOffPolicy(backOffPolicy);

        return retryTemplate;
    }
}

文章作者: 烽火戏诸诸诸侯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
  目录