一、前言
在实际项目中,往往在某些特定的场景下,我们需要实现接口调用异常的重试机制,比如在跨平台的业务中,需要调用第三方接口实现某些功能,难免会遇到一些网络问题,这时候需要加入重试机制了。
二、如何实现?
第一种:基于spring retry实现的重试。
1.引入maven依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2.编写重试配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
@Configuration
@EnableRetry
public class RetryConfig {
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
// 设置重试策略
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
// 最大重试次数
retryPolicy.setMaxAttempts(3);
retryTemplate.setRetryPolicy(retryPolicy);
// 设置重试间隔
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
// 重试间隔(毫秒)
backOffPolicy.setBackOffPeriod(1000);
retryTemplate.setBackOffPolicy(backOffPolicy);
return retryTemplate;
}
}
3.定义一个服务类,编写需要重试的方法
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@Service
public class RetryService {
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
public void callApiMethod() {
// 这里编写调用外部API的代码
// 如果调用失败会自动重试,最多重试3次,间隔1秒
}
}
4.可以配置重试监听器
如果想在重试发生时执行特定操作,可以添加一个实现了RetryListener接口的监听器类,并在RetryTemplate中设置该监听器。
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.listener.RetryListenerSupport;
import org.springframework.stereotype.Component;
@Component
public class MyRetryListener extends RetryListenerSupport {
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
System.out.println("重试发生,异常信息为:" + throwable.getMessage());
// 在这里可以记录日志或执行其他操作
super.onError(context, callback, throwable);
}
}
接着在RetryTemplate中注册这个监听器。
@Configuration
@EnableRetry
public class RetryConfig {
@Autowired
private MyRetryListener myRetryListener;
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
RetryTemplate retryTemplate = new RetryTemplate();
// 设置重试策略
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
// 最大重试次数
retryPolicy.setMaxAttempts(3);
retryTemplate.setRetryPolicy(retryPolicy);
// 设置重试间隔
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
// 重试间隔(毫秒)
backOffPolicy.setBackOffPeriod(1000);
retryTemplate.setBackOffPolicy(backOffPolicy);
// 注册重试监听器
retryTemplate.registerListener(myRetryListener);
return retryTemplate;
}
}
最后调用重试方法。
@Service
public class RetryService {
@Autowired
private RetryTemplate retryTemplate;
public void invokeApiWithRetry() {
retryTemplate.execute(context -> {
callApiMethod();
return null;
});
}
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000))
private void callApiMethod() {
// 调用外部API的代码
}
}
这时候调用失败时会重试,并且在重试发生出发监听,打印相应的异常日志。
第二种:使用网络工具的内置重试机制。
比如我们使用Apche HttpClient调用第三方接口时,它其实内置了相关的重试机制
在5.x的版本时:
CloseableHttpClient httpClient = HttpClients.custom()
.setRetryStrategy(new DefaultHttpRequestRetryStrategy(3,NEG_ONE_SECOND))
.build();
在上面的示例代码中,我们使用DefaultHttpRequestRetryStrategy来创建一个重试机制,最大重试次数为3次。如果请求失败,则会自动重试。
当然:Apache HttpClient还支持自定义重试策略,我们可以根据需要,通过实现RetryStrategy接口,自定义重写逻辑,如下:
CloseableHttpClient httpClient = HttpClients.custom()
.setRetryStrategy((response, executionCount, context) -> {
if (executionCount > 3) {
// 如果重试次数超过3次,则放弃重试
return false;
}
int code = response.getCode();
if (code >= 500 && code < 600) {
// 如果遇到服务器错误状态码,则进行重试
return true;
}
// 其他情况不进行重试
return false;
}) .build();
总结:
在请求重试的时候,我们也要注意一些关键点,以免因为重试,引发更多的问题,以下这些点我们需要考虑:
1.合理设置重试次数和重试间隔时间,避免频繁地发送请求,同时也不要设置过大的重试次数,以免影响系统的性能和响应时间。
2.在使用重试机制时,需要注意不要陷入死循环。如果请求一直失败,重试次数一直增加,可能会导致系统崩溃或者资源耗尽等问题。
3.考虑接口幂等性:如果请求是写操作,那么在重试时需要谨慎处理。
在重试过程中,需要考虑接口并发的问题,如果多个线程同时进行重试,可能会导致请求重复发送或请求顺序混乱等问题。可以使用锁或者分布式锁来解决并发问题。