天天看點

自己動手實踐 spring retry 重試架構自己動手搭建一個簡易的SpringBoot環境

前序

馬上過年了,預祝大家,新年快樂,少寫bug

什麼是spring retry?

spring retry是從spring batch獨立出來的一個能功能,主要實作了重試和熔斷。

什麼時候用?

遠端調用逾時、網絡突然中斷可以重試。對于重試是有場景限制的,不是什麼場景都适合重試,比如參數校驗不合法、寫操作等(要考慮寫是否幂等)都不适合重試。

怎麼用?

1,首先我們建立一個maven工程(如果不會,請移步 http://www.cnblogs.com/JJJ1990/p/8384386.html,大佬請忽略),然後在pom檔案中引入spring retry 的jar包,代碼如下:

1   <!-- spring-retry重試機制  -->
2         <dependency>
3             <groupId>org.springframework.retry</groupId>
4             <artifactId>spring-retry</artifactId>
5             <version>1.1.2.RELEASE</version>
6         </dependency>      

2,編寫重試部分代碼,我們直接在app類的main方法中實作

首先我們先制定好重試政策,也就是當異常發生後,我們重試幾次,每次間隔多久等

如下代碼中,第一行為建立一個重試模闆,第二行為制定一個簡單重試政策,特别注意最後的數字3,這就是我們設定的要重試的次數

1 final RetryTemplate retryTemplate = new RetryTemplate();
2         final SimpleRetryPolicy policy = new SimpleRetryPolicy(3, 
3                 Collections.<Class<? extends Throwable>,
4                 Boolean>singletonMap(Exception.class, true));      

3,下面再設定退避政策,注意第二行 2000為每次間隔的時間,機關ms,然後再将 重試政策和退避政策設定到重試模闆中如第3.4行

1 FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
2         fixedBackOffPolicy.setBackOffPeriod(2000);
3         retryTemplate.setRetryPolicy(policy);
4         retryTemplate.setBackOffPolicy(fixedBackOffPolicy);      

4,編寫重試業務部分代碼如下,主要是實作RetryCallback接口的 doWithRetry 方法,在這個裡面就是編寫主要的業務邏輯了。我在這塊模拟了一個異常,通過數組下标越界異常,來進行重試

1 final RetryCallback<String, Exception> retryCallback = new RetryCallback<String, Exception>() {
2             public String doWithRetry(RetryContext context) throws Exception {
3                 System.out.println(new Date());
4                 System.out.println("retryCallback");
5                 String [] str = new String [2];
6                 str[3] = "";
7                 return "1";
8             }
9         };      

5,編寫恢複回調代碼如下,也是實作了RecoveryCallback接口中的recover方法,這個方法的作用就是當第4步重試代碼按照重試政策執行完畢後,依舊異常,那就會執行下面的代碼,這樣你就可以通過下面的代碼,來規避異常

1 final RecoveryCallback<String> recoveryCallback = new RecoveryCallback<String>() {
2             public String recover(RetryContext context) throws Exception {
3                 System.out.println("recoveryCallback");
4                 return null;
5             }
6         };      

6,編寫重試模闆執行重試代碼及恢複回調代碼

1 try {
2             System.out.println("retryTemplate execute start");
3             String response = retryTemplate.execute(retryCallback, recoveryCallback);
4             System.out.println("retryTemplate execute end");
5         } catch (Exception e) {
6             e.printStackTrace();
7         }      

測試代碼

啟動程式,注意整個代碼是全部在main方法中實作的,我們直接啟動程式看列印的日志資訊,從日志資訊中可以得知,我們在啟動程式後先進入execute方法,然後執行retrycallback,但是每次執行的時候都有數組下标越覺異常,是以他就重試了3次,而且每次的時間間隔是我們設定的2秒,當第三次執行失敗後,就調用recovercallback方法,然後整個程式結束。

自己動手實踐 spring retry 重試架構自己動手搭建一個簡易的SpringBoot環境

退别政策有哪些?

1,我們上面的代碼中用的退别政策是固定時間間隔,還有其他幾種的退避政策大緻如下:

  • NoBackOffPolicy:無退避算法政策,每次重試時立即重試
  • FixedBackOffPolicy:固定時間的退避政策,需設定參數sleeper和backOffPeriod,sleeper指定等待政策,預設是Thread.sleep,即線程休眠,backOffPeriod指定休眠時間,預設1秒
  • UniformRandomBackOffPolicy:随機時間退避政策,需設定sleeper、minBackOffPeriod和maxBackOffPeriod,該政策在[minBackOffPeriod,maxBackOffPeriod之間取一個随機休眠時間,minBackOffPeriod預設500毫秒,maxBackOffPeriod預設1500毫秒
  • ExponentialBackOffPolicy:指數退避政策,需設定參數sleeper、initialInterval、maxInterval和multiplier,initialInterval指定初始休眠時間,預設100毫秒,maxInterval指定最大休眠時間,預設30秒,multiplier指定乘數,即下一次休眠時間為目前休眠時間*multiplier
  • ExponentialRandomBackOffPolicy:随機指數退避政策,引入随機乘數可以實作随機乘數回退

我們将第3步的代碼進行修改,如下:

1 ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();
2         exponentialBackOffPolicy.setInitialInterval(2000);
3         exponentialBackOffPolicy.setMultiplier(3);
4         exponentialBackOffPolicy.setMaxInterval(5000);
5         retryTemplate.setRetryPolicy(policy);
6         retryTemplate.setBackOffPolicy(exponentialBackOffPolicy);      

上述代碼中,2000為執行的時間間隔,3為倍數,5000為允許的最大間隔時間,執行代碼結果如下:

自己動手實踐 spring retry 重試架構自己動手搭建一個簡易的SpringBoot環境

如上圖,第一次執行和第二次執行間隔2秒,第二次和第三次的間隔本來是2*3=6秒,但是由于設定了最大間隔是以在5秒的時候就觸發了重試

重試業務中的異常不要捕獲

在我們的重試業務代碼中我們需要根據異常來進行重試,如果你在業務代碼中捕獲了異常會怎麼樣??我們修改下第4步代碼看看:

1 final RetryCallback<String, Exception> retryCallback = new RetryCallback<String, Exception>() {
 2             public String doWithRetry(RetryContext context) throws Exception {
 3                 System.out.println(new Date());
 4                 System.out.println("retryCallback");
 5                 try {
 6                     String [] str = new String [2];
 7                     str[3] = "";
 8                 } catch (Exception e) {
 9                     // TODO: handle exception
10                 }
11                 
12                 return "1";
13             }
14         };      

如上,很簡單,我們直接将數組異常try catch ,然後運作代碼結果如下

自己動手實踐 spring retry 重試架構自己動手搭建一個簡易的SpringBoot環境

如上圖,從資訊中可以看出,本來異常的代碼隻執行了一次,而且沒有調用恢複回調代碼。

是以如果你需要執行重試,那麼就不要捕獲你需要重試的異常資訊。

重要的話說三遍~~~

  

自己動手搭建一個簡易的SpringBoot環境

give me the ball!