本文目录导读:

在Java中实现接口重试有多种方式,从简单的手动重试到使用成熟的第三方库,以下是几种常见实现方案:
简单循环重试(手动实现)
public class SimpleRetryDemo {
public static void main(String[] args) {
SimpleRetryDemo demo = new SimpleRetryDemo();
String result = demo.retry(() -> {
// 模拟远程调用
return demo.callExternalService();
}, 3, 1000);
System.out.println("最终结果: " + result);
}
/**
* 通用重试方法
* @param callable 要执行的操作
* @param maxRetries 最大重试次数
* @param retryDelay 重试间隔(毫秒)
*/
public <T> T retry(Callable<T> callable, int maxRetries, long retryDelay) {
int retries = 0;
while (true) {
try {
return callable.call();
} catch (Exception e) {
retries++;
if (retries >= maxRetries) {
throw new RuntimeException("重试次数耗尽", e);
}
System.out.println("第" + retries + "次重试...");
try {
Thread.sleep(retryDelay);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException("重试被中断", ie);
}
}
}
}
// 模拟外部服务调用
private String callExternalService() {
if (Math.random() > 0.3) {
throw new RuntimeException("服务调用失败");
}
return "成功响应";
}
}
使用Spring Retry
// pom.xml 添加依赖
/*
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>2.0.5</version>
</dependency>
*/
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
// 配置重试策略
@Retryable(
value = {RemoteException.class, TimeoutException.class}, // 指定重试的异常类型
maxAttempts = 3, // 最大重试次数
backoff = @Backoff(delay = 1000, multiplier = 2) // 退避策略
)
public String createOrder(Order order) {
// 调用远程服务
return remoteService.createOrder(order);
}
// 所有重试失败后的降级方法
@Recover
public String recover(RemoteException e, Order order) {
// 日志记录
System.out.println("所有重试失败,执行降级逻辑");
return "降级结果";
}
}
使用Guava Retrying
// pom.xml 添加依赖
/*
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
*/
import com.github.rholder.retry.*;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
public class GuavaRetryDemo {
public static void main(String[] args) {
GuavaRetryDemo demo = new GuavaRetryDemo();
demo.retryWithGuava();
}
public void retryWithGuava() {
Callable<String> callable = () -> {
// 调用外部接口
if (Math.random() > 0.5) {
throw new RuntimeException("接口调用失败");
}
return "成功";
};
Retryer<String> retryer = RetryerBuilder.<String>newBuilder()
.retryIfExceptionOfType(RuntimeException.class) // 仅重试指定异常
.retryIfResult(result -> result.equals("失败")) // 根据结果重试
.withWaitStrategy(WaitStrategies.exponentialWait(100, 5000, TimeUnit.MILLISECONDS)) // 指数退避
.withStopStrategy(StopStrategies.stopAfterAttempt(5)) // 最多重试5次
.withRetryListener(new RetryListener() { // 重试监听器
@Override
public <V> void onRetry(Attempt<V> attempt) {
System.out.println("第" + attempt.getAttemptNumber() + "次尝试");
if (attempt.hasException()) {
System.out.println("异常: " + attempt.getExceptionCause().getMessage());
}
}
})
.build();
try {
String result = retryer.call(callable);
System.out.println("最终结果: " + result);
} catch (Exception e) {
System.out.println("重试全部失败: " + e.getMessage());
}
}
}
使用Apache HttpClient的重试机制
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
public class HttpClientRetryDemo {
public static void main(String[] args) {
// 自定义重试处理器
DefaultHttpRequestRetryHandler retryHandler =
new DefaultHttpRequestRetryHandler(3, true) { // 最多重试3次
@Override
public boolean retryRequest(IOException exception,
int executionCount,
HttpContext context) {
// 自定义重试逻辑
if (exception instanceof ConnectTimeoutException) {
// 连接超时重试
return executionCount < 5;
}
if (exception instanceof SocketTimeoutException) {
// 读取超时不重试
return false;
}
return super.retryRequest(exception, executionCount, context);
}
};
CloseableHttpClient httpClient = HttpClients.custom()
.setRetryHandler(retryHandler)
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(5000)
.setSocketTimeout(5000)
.build())
.build();
// 使用httpClient发送请求...
}
}
使用线程池的异步重试
import java.util.concurrent.*;
import java.util.function.Supplier;
public class AsyncRetryDemo {
private final ExecutorService executor = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
AsyncRetryDemo demo = new AsyncRetryDemo();
CompletableFuture<String> future = demo.asyncRetry(
() -> "result", // 业务逻辑
3,
1000
);
future.thenAccept(System.out::println)
.exceptionally(e -> {
System.out.println("最终失败: " + e.getMessage());
return null;
});
// 等待异步任务完成
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public <T> CompletableFuture<T> asyncRetry(
Supplier<T> supplier,
int maxRetries,
long retryDelay) {
CompletableFuture<T> future = new CompletableFuture<>();
executor.submit(() -> {
int retries = 0;
while (retries < maxRetries) {
try {
T result = supplier.get();
future.complete(result);
return;
} catch (Exception e) {
retries++;
System.out.println("第" + retries + "次重试");
if (retries >= maxRetries) {
future.completeExceptionally(e);
return;
}
try {
TimeUnit.MILLISECONDS.sleep(retryDelay);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
future.completeExceptionally(ie);
return;
}
}
}
});
return future;
}
public void shutdown() {
executor.shutdown();
}
}
自定义注解方式(AOP实现)
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retryable {
int maxRetries() default 3;
long retryDelay() default 1000;
Class<? extends Throwable>[] value() default {};
}
// 使用AOP实现重试逻辑
@Aspect
@Component
public class RetryAspect {
@Around("@annotation(retryable)")
public Object retry(ProceedingJoinPoint joinPoint, Retryable retryable) throws Throwable {
int maxRetries = retryable.maxRetries();
long retryDelay = retryable.retryDelay();
Class<? extends Throwable>[] retryExceptions = retryable.value();
int attempts = 0;
while (true) {
try {
return joinPoint.proceed();
} catch (Throwable e) {
attempts++;
if (attempts >= maxRetries) {
throw e; // 重试次数耗尽,抛出异常
}
// 检查是否应该重试
if (retryExceptions.length > 0 && !shouldRetry(e, retryExceptions)) {
throw e;
}
System.out.println("第" + attempts + "次重试...");
Thread.sleep(retryDelay);
}
}
}
private boolean shouldRetry(Throwable e, Class<? extends Throwable>[] retryExceptions) {
for (Class<? extends Throwable> clazz : retryExceptions) {
if (clazz.isInstance(e)) {
return true;
}
}
return false;
}
}
最佳实践建议
-
选择合适的重试策略:
- 网络相关的错误(超时、连接失败)适合重试
- 业务逻辑错误(参数错误、权限不足)不应重试
- 幂等性操作适合重试
-
退避策略:
- 固定延迟:适用于简单的重试场景
- 指数退避:避免雪崩效应
- 随机延迟:防止惊群效应
-
监控和日志:
- 记录每次重试的详细信息
- 设置重试次数的监控指标
- 超过阈值时发送告警
-
重试次数限制:
- 建议3-5次,避免过多重试
- 考虑业务SLA要求
选择哪种方案取决于项目的具体需求和技术栈,对于简单的项目,使用手动重试就足够了;对于复杂的微服务架构,推荐使用Spring Retry或Guava Retrying等成熟的库。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播