1、使用場景
- 在我們與下游通過http進行數據交互時,會約定接口協議,比如:雙方約定返回20000時,可以重新請求獲取正確的結果。
- 在進行http進行網絡通信時,經常會發生一些網絡層面的異常如:IOException:unexpected end of stream on Connection;SocketException:Broken pipe (Write failed)、Connection reset等,比較懶的做法是加上重試邏輯,如果你是技術宅,可以深究里面的深層原因。
- 其它任何可以重試的場景
2、常規的重試寫法
int retryTimes = 3;
for (int i = 0; i < retryTimes; i++) {
Result result = doSomethingPre();
if (result == 預期值){
doSomething();
berak;
}
}
有沒有覺得這段代碼就像一坨shit,如果這種重試需求很多,那么打開項目就會有滿屏shit。做為一個有追求的碼農,不能容忍這種事情發生,接下來Spring RetryTemplate閃亮登場。
3、Spring RetryTemplate的使用
- 引入依賴
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.4.RELEASE</version>
</dependency>
- 配置
既要重試,我們肯定要定義好重試的策略:重試的觸發條件,重試次數,時間間隔等要素。
RetryPolicy
下圖是RetryPolicy及實現類的關系圖,太大了,看不清,沒關系,我們只看最簡單最常用的SimpleRetryPolicy,它里面可以設置重試次數:setMaxAttempts();不設置的話,默認值是3次。
BackOffPolicy
顧名思義BackOffPolicy是退避策略,看一下他的實現類。
用ExponentialBackOffPolicy來舉例子,它是指數退避策略,需設置參數
initialInterval:初始休眠時間,默認100毫秒
multiplier:指定乘數,當前休眠時間*multiplier即為下一次的休眠時間;
maxInterval:指定最大休眠時間,默認30秒,避免multiplier過大引起無限期等待。
RetryTemplate
spring容器中注入RetryTemplate這個bean,並在該bean中設置上述兩個策略:
@Bean
public RetryTemplate simpleRetryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setRetryPolicy(new SimpleRetryPolicy());
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(3000);
backOffPolicy.setMultiplier(2);
backOffPolicy.setMaxInterval(15000);
retryTemplate.setBackOffPolicy(backOffPolicy);
return retryTemplate;
}
上面的配置通俗的說就是,最大重試三次,時間間隔為3,32,32*2,且時間間隔不大於15s。
- 使用
retryTemplate.execute(RetryCallback<T, E> retryCallback);
RetryCallback接口只有一個接口,即為函數式接口,可以使用lamda表達式來寫,簡潔且直觀。
最終寫法:retryTemplate.execute(retryContext -> {重試邏輯代碼});
這段為源代碼,可以省略,可以看到最終調用為RetryCallback接口的實現類,及lamda表達式
@Override
public final <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback) throws E {
return doExecute(retryCallback, null, null);
}
protected <T, E extends Throwable> T doExecute(RetryCallback<T, E> retryCallback,RecoveryCallback<T> recoveryCallback, RetryState state)throws E, ExhaustedRetryException {
......
return retryCallback.doWithRetry(context);
}
上述是retryTemplate最簡單的用法,它還有很多很強大的用法,有時間再來補充。