Spring Retry使用總結(一)


1. 介紹
在項目中,調用第三方接口響應比較慢,或者由於網絡抖動等原因,導致無響應的情況,就要用到重試機制.比較簡單成熟的方案就是使用spring-retry功能,spring-retry需要使用aop的特性,所以引入aspectj。
2. 項目依賴

        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>

3、spring對於重試機制的實現,給了幾個抽象。

  • BackOff:補償值,一般指失敗后多久進行重試的延遲值。
  • Sleeper:暫停應用的工具,通常用來應用補償值。
  • BackOffPolicy:補償策略,決定失敗后如何確定補償值。
  • RetryContext:重試上下文,代表了能被重試動作使用的資源。
  • RetryPolicy:重試策略,決定失敗能否重試。
  • RecoveryCallback:定義一個動作recover,在重試耗盡后的動作。
  • RetryCallback:具體的重試動作。
  • RetryOperations:通過傳遞RetryCallback,進行重試操作。
  • RetryState:重試狀態,通常包含一個重試的鍵值。
  • RetryStatistics和RetryListener,用來監控Retry的執行情況,並生成統計信息。

4、代碼示例

    @Retryable(value= {Exception.class}, maxAttempts = 3)
    public void call() throws Exception {
        System.out.println("do something...");
        throw new Exception("RPC調用異常");
    }

    @Recover
    public void recover(RemoteAccessException e) {
        System.out.println(e.getMessage());
    }
    @Retryable(maxAttempts = 3, backoff = @Backoff(value = 3000, multiplier = 1.5))
    public Customer getCustomer(String customerId) {
        if (true) {
            JSONArray data = retObj.getJSONArray("data");
            if (data != null && !data.isEmpty()) {
                return data.toJavaList(Customer.class).get(0);
            }
        } else {
            log.error("異常,{}", customerId);
            throw new RuntimeException("獲數據失敗");
        }
        return null;
    }

@Retryable被注解的方法發生異常時會重試。
@Retryable注解中的參數說明:

  • maxAttempts :最大重試次數,默認為3,如果要設置的重試次數為3,可以不寫;
  • value:拋出指定異常才會重試
  • include:和value一樣,默認為空,當exclude也為空時,所有異常都重試
  • exclude:指定不處理的異常,默認空,當include也為空時,所有異常都重試
  • backoff:重試等待策略,默認使用@Backoff@Backoff的value默認為1000L,我們設置為2000L。

@Backoff重試補償機制,默認沒有
@Backoff注解中的參數說明:

  • value:隔多少毫秒后重試,默認為1000L,我們設置為3000L;
  • delay:和value一樣,但是默認為0;
  • multiplier(指定延遲倍數)默認為0,表示固定暫停1秒后進行重試,如果把multiplier設置為1.5,則第一次重試為2秒,第二次為3秒,第三次為4.5秒。

5、@Recover注解
可以在指定方法上標記@Recover來開啟重試失敗后調用的方法(注意,需跟重處理方法在同一個類中)
@Recover:
當重試到達指定次數時,被注解的方法將被回調,可以在該方法中進行日志處理。需要注意的是發生的異常和入參類型一致時才會回調。

6、采坑提示
1、由於retry用到了aspect增強,所有會有aspect的坑,就是方法內部調用,會使aspect增強失效,那么retry當然也會失效。參考改鏈接;

public class demo {
    public void A() {
        B();
    }

    //這里B不會執行
    @Retryable(Exception.class)
    public void B() {
        throw new RuntimeException("retry...");
    }
}

2、maxAttemps參數解釋的是說重試次數,但是我再打斷點的時候發現這個=1時,方法一共只執行了一次。
3、recover回調報錯

org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method報錯顯示找不到recovery方法

解決recover回調報錯的方案就這這兩句話:

  • 異常類型需要與Recover方法參數類型保持一致
  • recover方法返回值需要與重試方法返回值保證一致

補充
對於非冪等的請求(比如新增,更新操作),千萬不要使用重試,對數據一致性會造成很大影響。


免責聲明!

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



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