前序
馬上過年了,預祝大家,新年快樂,少寫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環境
give me the ball!