Springboot RestTemplate如何实现接口调用的重试

<code>原创不易,请多多支持!对软件技术感兴趣的童鞋请关注我,后续技术分享更精彩。/<code> 

概述

后端微服务间接口调用,大多基于分布式http请求。而http的远程服务请求,往往存在很大的不可靠性,如网络不稳定,远程服务故障等。为保障调用端尽可能稳定可靠,获得预期数据,减少服务网络不稳定带来的影响,添加接口重试机制就变得尤为重要。本文介绍springboot中自带RestTemplate 接口组件,如何实现请求的自动重试机制。

实现

<code>public class RetryRestTemplate {


/**
* 失败重试默认3次,重试间隔时间=次数*100 ms.
* @return
*/
public static RestTemplate build(){
return build(3,100);
}

/**
* @param retryTimes 重试次数
* @param retryIntervalTime 每次重试间隔时间=重试次数*retryIntervalTime
* @return
*/
public static RestTemplate build(int retryTimes, long retryIntervalTime){
RestTemplate restTemplate = new RestTemplate();

//用UTF-8 StringHttpMessageConverter替换默认StringHttpMessageConverter
List<httpmessageconverter>> newMessageConverters = new ArrayList<>();
for(HttpMessageConverter> converter : restTemplate.getMessageConverters()){
if(converter instanceof StringHttpMessageConverter){
StringHttpMessageConverter messageConverter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
newMessageConverters.add(messageConverter);
}else {

newMessageConverters.add(converter);
}
}
restTemplate.setMessageConverters(newMessageConverters);

HttpClientBuilder httpClientBuilder = HttpClients.custom();
HttpRequestRetryHandler handler = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException exception, int curRetryCount, HttpContext context) {
try {
//重试延迟
Thread.sleep(curRetryCount*retryIntervalTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (curRetryCount > retryTimes) {
return false;
}
if (exception instanceof ConnectTimeoutException
|| exception instanceof NoHttpResponseException || exception instanceof ConnectException) {
return true;
}

HttpClientContext clientContext = HttpClientContext.adapt(context);
org.apache.http.HttpRequest request = clientContext.getRequest();
boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
if (idempotent) {
// 如果请求被认为是幂等的,那么就重试。即重复执行不影响程序其他效果的
return true;
}
return false;
}
};
httpClientBuilder.setRetryHandler(handler).setMaxConnTotal(400);

HttpClient httpClient = httpClientBuilder.build();

// httpClient连接配置,底层是配置RequestConfig
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
// 连接超时
clientHttpRequestFactory.setConnectTimeout(30000);
// 数据读取超时时间,即SocketTimeout
clientHttpRequestFactory.setReadTimeout(30000);
// 连接不够用的等待时间,不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的

clientHttpRequestFactory.setConnectionRequestTimeout(10000);
// 缓冲请求数据,默认值是true。通过POST或者PUT大量发送数据时,建议将此属性更改为false,以免耗尽内存。
// clientHttpRequestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(clientHttpRequestFactory);

//add cat monitor.
// CatRestTemplateInterceptor catRestTemplateInterceptor = new CatRestTemplateInterceptor();
// restTemplate.setInterceptors(Collections.singletonList(catRestTemplateInterceptor));

return restTemplate;
}
}/<httpmessageconverter>/<code>

以上代码可知,通过实现接口HttpRequestRetryHandler的retryRequest方法,可定制重试机制逻辑。该方法返回true时重试。其中IOException参数可用来定义请求发生那些异常时执行重试。curRetryCount参数为当前重试次数,可用来限制一次请求最多几次重试,通常最大3次。

总结

本文介绍springboot中自带restTemplate添加请求重试的方法。通过覆盖HttpRequestRetryHandler#retryRequest接口实现重试机制的定制化。IOException作为重试触发的判断条件,返回true重试触发。curRetryCount作为触发重试次数限制。同时支持重试的接口,在业务上需保证接口的幂等性,否则相同请求多次调用,可能导致数据的完整性和一致性。


分享到:


相關文章: