使用Spring RetryTemplate優雅的進行重試


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最簡單的用法,它還有很多很強大的用法,有時間再來補充。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM