本文目录导读:

手动循环重试(最简单)
public class SimpleRetryDemo {
public String callRemoteService() {
int maxRetries = 3;
int retryDelay = 1000; // 毫秒
for (int i = 0; i < maxRetries; i++) {
try {
// 调用远程服务
return doRemoteCall();
} catch (Exception e) {
if (i == maxRetries - 1) {
throw new RuntimeException("服务调用失败,已重试" + maxRetries + "次", e);
}
try {
Thread.sleep(retryDelay);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new RuntimeException("重试被中断", ex);
}
}
}
throw new RuntimeException("未知错误");
}
private String doRemoteCall() {
// 模拟远程调用
return "success";
}
}
缺点: 代码侵入性强,不易维护,不支持灵活配置
使用Spring Retry(推荐)
添加依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
启用重试
@Configuration
@EnableRetry
public class RetryConfig {
}
使用注解方式
@Service
public class OrderService {
@Retryable(
value = {RemoteAccessException.class, TimeoutException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 1000, multiplier = 2) // 指数退避
)
public String createOrder(Order order) {
// 调用远程订单服务
return remoteOrderService.create(order);
}
@Recover
public String recover(RemoteAccessException e, Order order) {
// 所有重试失败后的兜底处理
log.error("创建订单失败,进行降级处理", e);
return "fallback_order_id";
}
}
编程式重试
@Service
public class RetryTemplateService {
@Autowired
private RetryTemplate retryTemplate;
public String callWithRetry() {
return retryTemplate.execute(context -> {
// 重试次数检查
if (context.getRetryCount() > 0) {
log.info("第{}次重试", context.getRetryCount());
}
return remoteService.call();
}, context -> {
// 重试耗尽后的恢复逻辑
log.error("重试耗尽,执行降级");
return "fallback";
});
}
}
使用Resilience4j(功能更全面)
添加依赖
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-retry</artifactId>
</dependency>
配置重试
@Configuration
public class Resilience4jConfig {
@Bean
public Retry retry() {
RetryConfig config = RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofMillis(1000))
.retryExceptions(IOException.class, TimeoutException.class)
.ignoreExceptions(BusinessException.class) // 业务异常不重试
.build();
RetryRegistry registry = RetryRegistry.of(config);
return registry.retry("myService");
}
}
使用方式
@Service
public class PaymentService {
@Autowired
private Retry retry;
public String processPayment(Payment payment) {
// 方式1: 函数式
Supplier<String> retryableSupplier = Retry.decorateSupplier(
retry, () -> remotePaymentService.pay(payment)
);
return retryableSupplier.get();
// 方式2: 直接调用
// return retry.executeSupplier(() -> remotePaymentService.pay(payment));
}
}
使用Guava Retrying(轻量级)
添加依赖
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
实现示例
public class GuavaRetryDemo {
public String callWithRetry() {
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfExceptionOfType(IOException.class)
.retryIfResult(result -> result == null || result.isEmpty())
.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.withRetryListener(new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
log.info("第{}次重试, 耗时:{}ms",
attempt.getAttemptNumber(),
attempt.getDelaySinceFirstAttempt());
}
})
.build();
try {
return retryer.call(() -> remoteService.call());
} catch (ExecutionException | RetryException e) {
log.error("重试失败", e);
return "fallback";
}
}
}
关键设计原则
1 重试策略
// 固定延迟 @Backoff(delay = 1000) // 指数退避(推荐,避免雪崩) @Backoff(delay = 1000, multiplier = 2) // 1s, 2s, 4s, 8s... // 随机延迟(避免惊群效应) @Backoff(delay = 1000, random = true)
2 重试条件
// 只对特定异常重试
@Retryable(value = {NetworkException.class, TimeoutException.class})
// 忽略特定异常(业务异常不重试)
@Retryable(exceptionExpression = "message.contains('timeout')")
3 幂等性设计
// 重试接口必须是幂等的
public interface IdempotentService {
// 相同参数多次调用结果一致
String process(String orderId, @Idempotent String token);
}
4 熔断与重试结合
@CircuitBreaker(name = "orderService", fallbackMethod = "fallback")
@Retryable(maxAttempts = 3)
public String createOrder() {
// 先熔断保护,再重试
}
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 简单项目 | 手动循环 | 轻量,无需依赖 |
| Spring项目 | Spring Retry | 与Spring完美集成 |
| 微服务 | Resilience4j | 功能全面,支持熔断限流 |
| 快速开发 | Guava Retrying | API简洁,灵活配置 |
核心建议:
- 必须设置最大重试次数,防止无限重试
- 使用指数退避策略,避免雪崩效应
- 只重试可恢复的异常(网络超时、服务抖动)
- 业务异常不要重试(参数错误、余额不足)
- 重试接口必须幂等,多次调用结果一致
- 设置超时时间,避免长时间等待
- 做好监控和告警,及时发现重试频繁的问题
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播