一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - JAVA教程 - Java編程Retry重試機制實例詳解

Java編程Retry重試機制實例詳解

2021-03-31 13:54藍精靈lx JAVA教程

這篇文章主要介紹了Java編程Retry重試機制實例詳解,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下

本文研究的主要是Java編程Retry重試機制實例詳解,分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下

 

1、業務場景

 

應用中需要實現一個功能: 需要將數據上傳到遠程存儲服務,同時在返回處理成功情況下做其他操作。這個功能不復雜,分為兩個步驟:第一步調用遠程的Rest服務邏輯包裝給處理方法返回處理結果;第二步拿到第一步結果或者捕捉異常,如果出現錯誤或異常實現重試上傳邏輯,否則繼續邏輯操作。

 

2、常規解決方案演化

 

 

1)try-catch-redo簡單重試模式:

包裝正常上傳邏輯基礎上,通過判斷返回結果或監聽異常決策是否重試,同時為了解決立即重試的無效執行(假設異常是有外部執行不穩定導致的),休眠一定延遲時間重新執行功能邏輯。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void commonRetry(Map<String, Object> dataMap) throws InterruptedException {
    Map<String, Object> paramMap = Maps.newHashMap();
    paramMap.put("tableName", "creativeTable");
    paramMap.put("ds", "20160220");
    paramMap.put("dataMap", dataMap);
    boolean result = false;
    try {
      result = uploadToOdps(paramMap);
      if (!result) {
        Thread.sleep(1000);
        uploadToOdps(paramMap); //一次重試
      }
    } catch (Exception e) {
      Thread.sleep(1000);
      uploadToOdps(paramMap);//一次重試
    }
  }

 

2)try-catch-redo-retry strategy策略重試模式:

上述方案還是有可能重試無效,解決這個問題嘗試增加重試次數retrycount以及重試間隔周期interval,達到增加重試有效的可能性。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void commonRetry(Map<String, Object> dataMap) throws InterruptedException {
    Map<String, Object> paramMap = Maps.newHashMap();
    paramMap.put("tableName", "creativeTable");
    paramMap.put("ds", "20160220");
    paramMap.put("dataMap", dataMap);
    boolean result = false;
    try {
      result = uploadToOdps(paramMap);
      if (!result) {
        reuploadToOdps(paramMap,1000L,10);//延遲多次重試
      }
    } catch (Exception e) {
      reuploadToOdps(paramMap,1000L,10);//延遲多次重試
    }
  }

方案一和方案二存在一個問題:正常邏輯和重試邏輯強耦合,重試邏輯非常依賴正常邏輯的執行結果,對正常邏輯預期結果被動重試觸發,對于重試根源往往由于邏輯復雜被淹沒,可能導致后續運維對于重試邏輯要解決什么問題產生不一致理解。重試正確性難保證而且不利于運維,原因是重試設計依賴正常邏輯異常或重試根源的臆測。

 

3、優雅重試方案嘗試:

 

那有沒有可以參考的方案實現正常邏輯和重試邏輯解耦,同時能夠讓重試邏輯有一個標準化的解決思路?答案是有:那就是基于代理設計模式的重試工具,我們嘗試使用相應工具來重構上述場景。

 

1)應用命令設計模式解耦正常和重試邏輯:

命令設計模式具體定義不展開闡述,主要該方案看中命令模式能夠通過執行對象完成接口操作邏輯,同時內部封裝處理重試邏輯,不暴露實現細節,對于調用者來看就是執行了正常邏輯,達到解耦的目標,具體看下功能實現。(類圖結構)

Java編程Retry重試機制實例詳解

IRetry約定了上傳和重試接口,其實現類OdpsRetry封裝ODPS上傳邏輯,同時封裝重試機制和重試策略。與此同時使用recover方法在結束執行做恢復操作。

而我們的調用者LogicClient無需關注重試,通過重試者Retryer實現約定接口功能,同時 Retryer需要對重試邏輯做出響應和處理, Retryer具體重試處理又交給真正的IRtry接口的實現類OdpsRetry完成。通過采用命令模式,優雅實現正常邏輯和重試邏輯分離,同時通過構建重試者角色,實現正常邏輯和重試邏輯的分離,讓重試有更好的擴展性。

 

2)spring-retry 規范正常和重試邏輯

spring-retry是一個開源工具包,目前可用的版本為1.1.2.RELEASE,該工具把重試操作模板定制化,可以設置重試策略和回退策略。同時重試執行實例保證線程安全,具體場景操作實例如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public void upload(final Map<String, Object> map) throws Exception {
    // 構建重試模板實例
    RetryTemplate retryTemplate = new RetryTemplate();
    // 設置重試策略,主要設置重試次數
    SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true));
    // 設置重試回退操作策略,主要設置重試間隔時間
    FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
    fixedBackOffPolicy.setBackOffPeriod(100);
    retryTemplate.setRetryPolicy(policy);
    retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
    // 通過RetryCallback 重試回調實例包裝正常邏輯邏輯,第一次執行和重試執行執行的都是這段邏輯
    final RetryCallback<Object, Exception> retryCallback = new RetryCallback<Object, Exception>() {
      //RetryContext 重試操作上下文約定,統一spring-try包裝 
      public Object doWithRetry(RetryContext context) throws Exception {
        System.out.println("do some thing");
        Exception e = uploadToOdps(map);
        System.out.println(context.getRetryCount());
        throw e;//這個點特別注意,重試的根源通過Exception返回
      }
    };
    // 通過RecoveryCallback 重試流程正常結束或者達到重試上限后的退出恢復操作實例
    final RecoveryCallback<Object> recoveryCallback = new RecoveryCallback<Object>() {
      public Object recover(RetryContext context) throws Exception {
        System.out.println("do recory operation");
        return null;
      }
    };
    try {
      // 由retryTemplate 執行execute方法開始邏輯執行
      retryTemplate.execute(retryCallback, recoveryCallback);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

簡單剖析下案例代碼,RetryTemplate 承擔了重試執行者的角色,它可以設置SimpleRetryPolicy(重試策略,設置重試上限,重試的根源實體),FixedBackOffPolicy(固定的回退策略,設置執行重試回退的時間間隔)。RetryTemplate通過execute提交執行操作,需要準備RetryCallback 和RecoveryCallback 兩個類實例,前者對應的就是重試回調邏輯實例,包裝正常的功能操作,RecoveryCallback實現的是整個執行操作結束的恢復操作實例。

RetryTemplate的execute 是線程安全的,實現邏輯使用ThreadLocal保存每個執行實例的RetryContext執行上下文。

Spring-retry工具雖能優雅實現重試,但是存在兩個不友好設計:一個是 重試實體限定為Throwable子類,說明重試針對的是可捕捉的功能異常為設計前提的,但是我們希望依賴某個數據對象實體作為重試實體,但Sping-retry框架必須強制轉換為Throwable子類。另一個就是重試根源的斷言對象使用的是doWithRetry的Exception 異常實例,不符合正常內部斷言的返回設計。

Spring Retry提倡以注解的方式對方法進行重試,重試邏輯是同步執行的,重試的“失敗”針對的是Throwable,如果你要以返回值的某個狀態來判定是否需要重試,可能只能通過自己判斷返回值然后顯式拋出異常了。

Spring 對于Retry的抽象

“抽象”是每個程序員必備的素質。對于資質平平的我來說,沒有比模仿與理解優秀源碼更好地進步途徑了吧。為此,我將其核心邏輯重寫了一遍...下面就看看Spring Retry對于“重試”的抽象。

Java編程Retry重試機制實例詳解

Spring retry相關接口.jpg

  • RetryCallback: 封裝你需要重試的業務邏輯(上文中的doSth)
  • RecoverCallback:封裝在多次重試都失敗后你需要執行的業務邏輯(上文中的doSthWhenStillFail)
  • RetryContext: 重試語境下的上下文,可用于在多次Retry或者Retry 和Recover之間傳遞參數或狀態(在多次doSth或者doSth與doSthWhenStillFail之間傳遞參數)
  • RetryOperations : 定義了“重試”的基本框架(模板),要求傳入RetryCallback,可選傳入RecoveryCallback;
  • RetryListener:典型的“監聽者”,在重試的不同階段通知“監聽者”(例如doSth,wait等階段時通知)
  • RetryPolicy : 重試的策略或條件,可以簡單的進行多次重試,可以是指定超時時間進行重試(上文中的someCondition)
  • BackOffPolicy: 重試的回退策略,在業務邏輯執行發生異常時。如果需要重試,我們可能需要等一段時間(可能服務器過于繁忙,如果一直不間隔重試可能拖垮服務器),當然這段時間可以是0,也可以是固定的,可以是隨機的(參見tcp的擁塞控制算法中的回退策略)。回退策略在上文中體現為wait();
  • RetryTemplate :RetryOperations的具體實現,組合了RetryListener[],BackOffPolicy,RetryPolicy。

 

3)guava-retryer 分離正常和重試邏輯

Guava retryer工具與spring-retry類似,都是通過定義重試者角色來包裝正常邏輯重試,但是Guava retryer有更優的策略定義,在支持重試次數和重試頻度控制基礎上,能夠兼容支持多個異常或者自定義實體對象的重試源定義,讓重試功能有更多的靈活性。Guava Retryer也是線程安全的,入口調用邏輯采用的是Java.util.concurrent.Callable的call方法,示例代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public void uploadOdps(final Map<String, Object> map) {
    // RetryerBuilder 構建重試實例 retryer,可以設置重試源且可以支持多個重試源,可以配置重試次數或重試超時時間,以及可以配置等待時間間隔
    Retryer<Boolean> retryer = RetryerBuilder.<Boolean> newBuilder()
        .retryIfException().//設置異常重試源
        retryIfResult(new Predicate<Boolean>() {//設置自定義段元重試源,
      @Override
      public boolean apply(Boolean state) {//特別注意:這個apply返回true說明需要重試,與操作邏輯的語義要區分
        return true;
      }
    })
    .withStopStrategy(StopStrategies.stopAfterAttempt(5))//設置重試5次,同樣可以設置重試超時時間
    .withWaitStrategy(WaitStrategies.fixedWait(100L, TimeUnit.MILLISECONDS)).build();//設置每次重試間隔
 
    try {
      //重試入口采用call方法,用的是java.util.concurrent.Callable<V>的call方法,所以執行是線程安全的
      boolean result = retryer.call(new Callable<Boolean>() { 
        @Override
        public Boolean call() throws Exception {
          try {
            //特別注意:返回false說明無需重試,返回true說明需要繼續重試
            return uploadToOdps(map);
          } catch (Exception e) {
            throw new Exception(e);
          }
        }
      });
 
    } catch (ExecutionException e) {
    } catch (RetryException ex) {
    }
  }

示例代碼原理分析:

RetryerBuilder是一個factory創建者,可以定制設置重試源且可以支持多個重試源,可以配置重試次數或重試超時時間,以及可以配置等待時間間隔,創建重試者Retryer實例。

RetryerBuilder的重試源支持Exception異常對象 和自定義斷言對象,通過retryIfException 和retryIfResult設置,同時支持多個且能兼容。

RetryerBuilder的等待時間和重試限制配置采用不同的策略類實現,同時對于等待時間特征可以支持無間隔和固定間隔方式。

Retryer 是重試者實例,通過call方法執行操作邏輯,同時封裝重試源操作。

優雅重試共性和原理

正常和重試優雅解耦,重試斷言條件實例或邏輯異常實例是兩者溝通的媒介。
約定重試間隔,差異性重試策略,設置重試超時時間,進一步保證重試有效性以及重試流程穩定性。
都使用了命令設計模式,通過委托重試對象完成相應的邏輯操作,同時內部封裝實現重試邏輯。
Spring-tryer和guava-tryer工具都是線程安全的重試,能夠支持并發業務場景的重試邏輯正確性。

優雅重試適用場景

功能邏輯中存在不穩定依賴場景,需要使用重試獲取預期結果或者嘗試重新執行邏輯不立即結束。比如遠程接口訪問,數據加載訪問,數據上傳校驗等等。
對于異常場景存在需要重試場景,同時希望把正常邏輯和重試邏輯解耦。
對于需要基于數據媒介交互,希望通過重試輪詢檢測執行邏輯場景也可以考慮重試方案。

 

總結

 

以上就是本文關于Java編程Retry重試機制實例詳解的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

原文鏈接:http://blog.csdn.net/liuxiao723846/article/details/78866879

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 香蕉久久久久 | 日韩毛片基地一区二区三区 | 嫩草影院永久在线播放 | 亚洲国产精品嫩草影院久久 | 幻女free性摘花第一次 | 久久精品动漫网一区二区 | 娇妻在床上迎合男人 | ai换脸明星造梦工厂忘忧草 | 精品精品国产yyy5857香蕉 | 52zfl宅福利yxpjw | 免费国产一级观看完整版 | 湿好紧太硬了我太爽了 | 亚洲精品久久久成人 | 5g影院天天5g天天爽大陆 | 欧美日韩国产另类一区二区三区 | 好男人好资源在线观看免费 | 亚洲第一永久色 | 夫承子液by免费阅读 | h日本漫画全彩在线观看 | 狠狠色96视频 | 热99re国产久热在线 | 俺去俺来也www色官网免费的 | 国产成人亚洲影视在线 | 日韩高清成人毛片不卡 | 国产高清在线播放刘婷91 | 7788理论片在线观看 | 日本精品vide·ssex日本 | 精品一区二区三区高清免费不卡 | 69老司机亚洲精品一区 | av72成人| 高h文3p双龙| 古代翁熄乩伦小说h | 亚洲AV无码A片在线观看蜜桃 | 天天做天天爱天天操 | 国产rpg迷雾之风冷狐破解 | 亚洲成av人片天堂网 | 欧美日韩三区 | yellow高清视频日本动漫 | 我与岳乱短篇小说 | 日本b站一卡二不卡三卡四卡 | 禁欲天堂|