1. 程式人生 > >自己動手實踐 spring retry 重試框架

自己動手實踐 spring retry 重試框架

null for llb ati dba 行為 turn .com min

前序

馬上過年了,預祝大家,新年快樂,少寫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方法,然後整個程序結束。

技術分享圖片

退別策略有哪些?

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為允許的最大間隔時間,執行代碼結果如下:

技術分享圖片

如上圖,第一次執行和第二次執行間隔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 ,然後運行代碼結果如下

技術分享圖片

如上圖,從信息中可以看出,本來異常的代碼只執行了一次,而且沒有調用恢復回調代碼。

所以如果你需要執行重試,那麽就不要捕獲你需要重試的異常信息。

所以如果你需要執行重試,那麽就不要捕獲你需要重試的異常信息。

所以如果你需要執行重試,那麽就不要捕獲你需要重試的異常信息。

重要的話說三遍~~~

  

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

自己動手實踐 spring retry 重試框架