自己動手實踐 spring retry 重試框架
前序
馬上過年了,預祝大家,新年快樂,少寫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 重試框架