前言
在分布式系统和微服务架构盛行的当下,服务调用失败的情况时有发生,网络波动、服务过载或临时故障等因素都可能导致调用失败。为提升系统可用性,重试机制成为处理临时性故障的有效手段。本文将探讨Spring Boot中4种重试机制的实现方案,助力开发者根据项目需求精准选型。
一.Guava Retrying
基本原理
Guava Retrying 是 Google Guava 库提供的重试机制,通过构建器模式实现灵活配置,可自定义重试条件、停止策略、等待策略等,为开发者提供了强大的控制能力。
使用方法
主要采用编程方式,通过RetryerBuilder构建Retryer实例,设置重试条件、等待策略、停止策略等。还可添加重试监听器,在重试过程中记录日志或执行其他操作。也可将Retryer定义为可复用的bean,提高代码复用性。
二.Spring Retry
基本原理
Spring Retry作为Spring官方出品的重试框架,借助AOP实现方法调用重试。核心组件涵盖定义重试操作接口的RetryOperations,其默认实现RetryTemplate,以及定义重试条件的RetryPolicy、控制重试间隔的BackOffPolicy和最终失败恢复策略的RecoveryCallback。当方法调用失败,它会依据配置策略自动重试,直至成功或达到最大重试次数。
使用方法
注解方式:使用@Retryable注解标记需重试的方法,指定触发重试的异常类型、最大重试次数和退避策略。@Recover注解用于定义重试失败后的恢复方法,代码简洁直观,适用于简单场景。
编程方式:通过注入RetryTemplate实例,在方法内调用execute方法,传入重试业务逻辑和失败恢复逻辑。还可自定义RetryTemplate的重试策略和退避策略,满足复杂业务需求。
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Override
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 2))
public void addOrder() {
System.out.println("重试...");
int i = 3 / 0;
// addOrder
}
@Recover
public void recover(RuntimeException e) {
log.error("达到最大重试次数", e);
}
}
public void normalSpringRetry() {
// 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试
Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
exceptionMap.put(RetryException.class, true);
// 构建重试模板实例
RetryTemplate retryTemplate = new RetryTemplate();
// 堆代码 duidaima.com
// 设置重试回退操作策略,主要设置重试间隔时间
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
long fixedPeriodTime = 1000L;
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
// 设置重试策略,主要设置重试次数
int maxRetryTimes = 3;
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
retryTemplate.setRetryPolicy(retryPolicy);
retryTemplate.setBackOffPolicy(backOffPolicy);
Boolean execute = retryTemplate.execute(
//RetryCallback
retryContext -> {
String hello = helloService.hello();
log.info("调用的结果:{}", hello);
returntrue;
},
// RecoverCallBack
retryContext -> {
//RecoveryCallback
log.info("已达到最大重试次数");
returnfalse;
}
);
}
三.Resilience4j Retry
基本原理
Resilience4j Retry受Netflix Hystrix启发,是轻量级容错库。它采用函数式编程风格和装饰器模式实现重试功能,具备基于函数式接口、无外部依赖、可与其他容错机制无缝集成以及提供丰富监控指标等特性。
使用方法
注解方式:使用@Retry注解标记方法,指定重试实例名称和降级方法,简洁方便,适用于简单业务场景。
编程方式:从RetryRegistry获取已配置的重试实例,使用Retry.decorateCheckedSupplier方法装饰业务方法,在try-catch块中执行重试逻辑并处理失败情况,灵活性更高。
resilience4j.retry:
instances:
backendService:
maxAttempts: 3
waitDuration: 1s
enableExponentialBackoff: true
exponentialBackoffMultiplier: 2
retryExceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException
@Service
public class OrderServiceImpl implements OrderService {
@Override
@Retry(name = "addOrder", fallbackMethod = "recover")
public void addOrder() {
System.out.println("重试...");
int i = 3 / 0;
// addOrder
}
public void recover((String param, Exception ex) {
log.error("达到最大重试次数", e);
}
}
@Service
public class HelloService {
private final RetryRegistry retryRegistry;
public String executeWithRetry(String param) {
// 获取已配置的重试实例
Retry retry = retryRegistry.retry("helloService");
// 创建一个可重试的函数
CheckedFunction0<String> retryableFunction = Retry.decorateCheckedSupplier(
retry, () -> callHelloService(param));
try {
// 执行重试函数
return retryableFunction.apply();
} catch (Throwable throwable) {
return"降级响应: " + param;
}
}
private String callHelloService(String param) throws IOException {
if (Math.random() > 0.7) {
throw new IOException("服务连接失败");
}
return"后端服务响应: " + param;
}
}
四.Failsafe
基本原理
Failsafe专注于高性能和低延迟场景,支持同步和异步重试,具有灵活的重试策略和极少的依赖。其设计目标是提供简洁高效的重试机制,让开发者能轻松应对各种重试需求。
使用方法
主要通过编程方式,利用流式API进行配置。可配置重试策略,包括处理的异常类型、最大重试次数、延迟时间、最大持续时间、退避策略等,还可添加重试和失败监听器。同时支持异步重试和带降级的重试,满足不同业务场景需求。也可将重试策略和降级策略定义为可复用的bean,提升代码复用性。
@Slf4j
@Service
public class FailsafeService {
public String executeWithRetry(String param) {
return Failsafe.with(
// 配置重试策略
RetryPolicy.<String>builder()
.handle(IOException.class, TimeoutException.class)
.withMaxRetries(3)
.withDelay(Duration.ofSeconds(1))
.withMaxDuration(Duration.ofSeconds(10))
.withBackoff(Duration.ofMillis(100), Duration.ofSeconds(2))
.onRetry(event -> log.info("第{}次重试,上次异常: {}",
event.getAttemptCount(),
event.getLastException().getMessage()))
.onFailure(event -> log.error("重试失败,尝试次数: {}, 总耗时: {}ms",
event.getAttemptCount(),
event.getElapsedTime().toMillis()))
.build()
)
.get(() -> {
log.info("执行操作,参数: {}", param);
// 模拟操作
if (Math.random() > 0.7) {
throw new IOException("操作暂时失败");
}
return"操作成功: " + param;
});
}
// 异步重试示例
public CompletableFuture<String> executeWithRetryAsync(String param) {
return Failsafe.with(
RetryPolicy.<String>builder()
.handle(IOException.class)
.withMaxRetries(3)
.withBackoff(Duration.ofMillis(100), Duration.ofSeconds(1))
.build()
)
.getAsync(() -> {
log.info("异步执行操作,参数: {}", param);
// 模拟异步操作
if (Math.random() > 0.7) {
throw new IOException("异步操作暂时失败");
}
return"异步操作成功: " + param;
});
}
// 带降级的重试示例
public String executeWithFallback(String param) {
return Failsafe.with(
RetryPolicy.<String>builder()
.handle(IOException.class)
.withMaxRetries(3)
.build(),
// 降级策略
Fallback.of(e -> "降级响应: " + param)
)
.get(() -> {
// 业务逻辑
if (Math.random() > 0.7) {
throw new IOException("操作失败");
}
return"操作成功: " + param;
});
}
}
总结

在实际开发中,开发者可根据业务场景的特点,灵活运用这些重试机制,提升系统的容错能力和用户体验。