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作為觸發重試次數限制。同時支持重試的接口,在業務上需保證接口的冪等性,否則相同請求多次調用,可能導致數據的完整性和一致性。


分享到:


相關文章: