背景
在项目中,偶尔出现一些超时或者请求异常的情况,需要进行重试,这个时候,你会怎么处理?
Spring Retry
Spring Retry是Spring框架的一个扩展模块,专门用于提供声明式重试的功能。
1、添加依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
2、启动类增加@EnableRetry注解
3、使用
1)方式1:在对应方法上加上@Retryable注解
@GetMapping("/spring-retry")
@Retryable(maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))// 重试5次,初始间隔1秒,间隔乘数2
public String springRetry() {
System.out.println(new Date() + "请求中...");
int i = 1 / 0;
return "请求成功";
}
2)方式2:注入RetryTemplate使用
添加配置
@Configuration
@EnableRetry
public class RetryConfig {
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(1000); // 初始间隔 1 秒
backOffPolicy.setMultiplier(2.0); // 间隔乘数
backOffPolicy.setMaxInterval(10000); // 最大间隔 10 秒
retryTemplate.setBackOffPolicy(backOffPolicy);
SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
simpleRetryPolicy.setMaxAttempts(3);
retryTemplate.setRetryPolicy(simpleRetryPolicy); // 最大重试次数
return retryTemplate;
}
}
依赖注入使用
@Autowired
private RetryTemplate retryTemplate;
@GetMapping("/spring-retry2")
public String springRetry2() {
return retryTemplate.execute(context -> {
System.out.println(new Date() + "请求中...");
int i = 1 / 0;
return "请求成功";
});
}
自定义实现
自定义实现重试逻辑,思路大概就是使用循环、条件判断、线程休眠等。
1、工具类
public class RetryUtils {
private static final int MAX_RETRIES = 3; // 最大重试次数
private static final long BASE_BACKOFF_MILLIS = 1000; // 基础退避时间(毫秒)
private static final double BACKOFF_MULTIPLIER = 2.0; // 退避时间倍数
/**
* 执行带重试逻辑的任务
*
* @param task 需要重试的任务
* @param <T> 任务返回类型
* @return 任务执行结果
* @throws Exception 如果所有重试都失败,则抛出异常
*/
public static <T> T executeWithRetry(Callable<T> task) throws Exception {
int attempt = 0;
long backoffMillis = BASE_BACKOFF_MILLIS;
while (true) {
attempt++;
try {
return task.call(); // 尝试执行任务
} catch (Exception e) {
if (attempt > MAX_RETRIES) {
throw new RuntimeException("超过最大重试次数");
}
// 应用退避策略,等待一段时间后重试
TimeUnit.MILLISECONDS.sleep(backoffMillis);
backoffMillis = (long) (backoffMillis * BACKOFF_MULTIPLIER);
}
}
}
}
2、使用
@GetMapping("/customize")
public String customize() throws Exception {
return RetryUtils.executeWithRetry(() -> {
System.out.println(new Date() + "请求中...");
int i = 1 / 0;
return "请求成功";
});
}
总结
总的来说,上面主要介绍了Spring Retry和自定义实现,都是同步的,除此之外,Guava、Resilience4j等框架也是支持的。
Google的Guava库也提供了简单的重试机制,可以使用其Retryer类来创建重试策略。Guava的重试机制较为轻量级,易于集成到现有的项目中。
Resilience4j是一个轻量级的容错库,它提供了重试、熔断、限流等功能。Resilience4j的Retry模块允许你配置重试策略,并可以与其他容错机制结合使用。