亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java編程Retry重試機(jī)制實(shí)例詳解

 更新時(shí)間:2018年02月05日 11:43:23   作者:藍(lán)精靈lx  
這篇文章主要介紹了Java編程Retry重試機(jī)制實(shí)例詳解,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下

本文研究的主要是Java編程Retry重試機(jī)制實(shí)例詳解,分享了相關(guān)代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下

1、業(yè)務(wù)場(chǎng)景

應(yīng)用中需要實(shí)現(xiàn)一個(gè)功能: 需要將數(shù)據(jù)上傳到遠(yuǎn)程存儲(chǔ)服務(wù),同時(shí)在返回處理成功情況下做其他操作。這個(gè)功能不復(fù)雜,分為兩個(gè)步驟:第一步調(diào)用遠(yuǎn)程的Rest服務(wù)邏輯包裝給處理方法返回處理結(jié)果;第二步拿到第一步結(jié)果或者捕捉異常,如果出現(xiàn)錯(cuò)誤或異常實(shí)現(xiàn)重試上傳邏輯,否則繼續(xù)邏輯操作。

2、常規(guī)解決方案演化

1)try-catch-redo簡(jiǎn)單重試模式:

包裝正常上傳邏輯基礎(chǔ)上,通過(guò)判斷返回結(jié)果或監(jiān)聽(tīng)異常決策是否重試,同時(shí)為了解決立即重試的無(wú)效執(zhí)行(假設(shè)異常是有外部執(zhí)行不穩(wěn)定導(dǎo)致的),休眠一定延遲時(shí)間重新執(zhí)行功能邏輯。

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策略重試模式:

上述方案還是有可能重試無(wú)效,解決這個(gè)問(wèn)題嘗試增加重試次數(shù)retrycount以及重試間隔周期interval,達(dá)到增加重試有效的可能性。

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);//延遲多次重試 
    } 
  } 

方案一和方案二存在一個(gè)問(wèn)題:正常邏輯和重試邏輯強(qiáng)耦合,重試邏輯非常依賴(lài)正常邏輯的執(zhí)行結(jié)果,對(duì)正常邏輯預(yù)期結(jié)果被動(dòng)重試觸發(fā),對(duì)于重試根源往往由于邏輯復(fù)雜被淹沒(méi),可能導(dǎo)致后續(xù)運(yùn)維對(duì)于重試邏輯要解決什么問(wèn)題產(chǎn)生不一致理解。重試正確性難保證而且不利于運(yùn)維,原因是重試設(shè)計(jì)依賴(lài)正常邏輯異?;蛑卦嚫吹囊軠y(cè)。

3、優(yōu)雅重試方案嘗試:

那有沒(méi)有可以參考的方案實(shí)現(xiàn)正常邏輯和重試邏輯解耦,同時(shí)能夠讓重試邏輯有一個(gè)標(biāo)準(zhǔn)化的解決思路?答案是有:那就是基于代理設(shè)計(jì)模式的重試工具,我們嘗試使用相應(yīng)工具來(lái)重構(gòu)上述場(chǎng)景。

1)應(yīng)用命令設(shè)計(jì)模式解耦正常和重試邏輯:

命令設(shè)計(jì)模式具體定義不展開(kāi)闡述,主要該方案看中命令模式能夠通過(guò)執(zhí)行對(duì)象完成接口操作邏輯,同時(shí)內(nèi)部封裝處理重試邏輯,不暴露實(shí)現(xiàn)細(xì)節(jié),對(duì)于調(diào)用者來(lái)看就是執(zhí)行了正常邏輯,達(dá)到解耦的目標(biāo),具體看下功能實(shí)現(xiàn)。(類(lèi)圖結(jié)構(gòu))

IRetry約定了上傳和重試接口,其實(shí)現(xiàn)類(lèi)OdpsRetry封裝ODPS上傳邏輯,同時(shí)封裝重試機(jī)制和重試策略。與此同時(shí)使用recover方法在結(jié)束執(zhí)行做恢復(fù)操作。

而我們的調(diào)用者LogicClient無(wú)需關(guān)注重試,通過(guò)重試者Retryer實(shí)現(xiàn)約定接口功能,同時(shí) Retryer需要對(duì)重試邏輯做出響應(yīng)和處理, Retryer具體重試處理又交給真正的IRtry接口的實(shí)現(xiàn)類(lèi)OdpsRetry完成。通過(guò)采用命令模式,優(yōu)雅實(shí)現(xiàn)正常邏輯和重試邏輯分離,同時(shí)通過(guò)構(gòu)建重試者角色,實(shí)現(xiàn)正常邏輯和重試邏輯的分離,讓重試有更好的擴(kuò)展性。

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

spring-retry是一個(gè)開(kāi)源工具包,目前可用的版本為1.1.2.RELEASE,該工具把重試操作模板定制化,可以設(shè)置重試策略和回退策略。同時(shí)重試執(zhí)行實(shí)例保證線(xiàn)程安全,具體場(chǎng)景操作實(shí)例如下:

public void upload(final Map<String, Object> map) throws Exception { 
    // 構(gòu)建重試模板實(shí)例 
    RetryTemplate retryTemplate = new RetryTemplate(); 
    // 設(shè)置重試策略,主要設(shè)置重試次數(shù) 
    SimpleRetryPolicy policy = new SimpleRetryPolicy(3, Collections.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true)); 
    // 設(shè)置重試回退操作策略,主要設(shè)置重試間隔時(shí)間 
    FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy(); 
    fixedBackOffPolicy.setBackOffPeriod(100); 
    retryTemplate.setRetryPolicy(policy); 
    retryTemplate.setBackOffPolicy(fixedBackOffPolicy); 
    // 通過(guò)RetryCallback 重試回調(diào)實(shí)例包裝正常邏輯邏輯,第一次執(zhí)行和重試執(zhí)行執(zhí)行的都是這段邏輯 
    final RetryCallback<Object, Exception> retryCallback = new RetryCallback<Object, Exception>() { 
      //RetryContext 重試操作上下文約定,統(tǒng)一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;//這個(gè)點(diǎn)特別注意,重試的根源通過(guò)Exception返回 
      } 
    }; 
    // 通過(guò)RecoveryCallback 重試流程正常結(jié)束或者達(dá)到重試上限后的退出恢復(fù)操作實(shí)例 
    final RecoveryCallback<Object> recoveryCallback = new RecoveryCallback<Object>() { 
      public Object recover(RetryContext context) throws Exception { 
        System.out.println("do recory operation"); 
        return null; 
      } 
    }; 
    try { 
      // 由retryTemplate 執(zhí)行execute方法開(kāi)始邏輯執(zhí)行 
      retryTemplate.execute(retryCallback, recoveryCallback); 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
  } 

簡(jiǎn)單剖析下案例代碼,RetryTemplate 承擔(dān)了重試執(zhí)行者的角色,它可以設(shè)置SimpleRetryPolicy(重試策略,設(shè)置重試上限,重試的根源實(shí)體),F(xiàn)ixedBackOffPolicy(固定的回退策略,設(shè)置執(zhí)行重試回退的時(shí)間間隔)。RetryTemplate通過(guò)execute提交執(zhí)行操作,需要準(zhǔn)備RetryCallback 和RecoveryCallback 兩個(gè)類(lèi)實(shí)例,前者對(duì)應(yīng)的就是重試回調(diào)邏輯實(shí)例,包裝正常的功能操作,RecoveryCallback實(shí)現(xiàn)的是整個(gè)執(zhí)行操作結(jié)束的恢復(fù)操作實(shí)例。

RetryTemplate的execute 是線(xiàn)程安全的,實(shí)現(xiàn)邏輯使用ThreadLocal保存每個(gè)執(zhí)行實(shí)例的RetryContext執(zhí)行上下文。

Spring-retry工具雖能優(yōu)雅實(shí)現(xiàn)重試,但是存在兩個(gè)不友好設(shè)計(jì):一個(gè)是 重試實(shí)體限定為T(mén)hrowable子類(lèi),說(shuō)明重試針對(duì)的是可捕捉的功能異常為設(shè)計(jì)前提的,但是我們希望依賴(lài)某個(gè)數(shù)據(jù)對(duì)象實(shí)體作為重試實(shí)體,但Sping-retry框架必須強(qiáng)制轉(zhuǎn)換為T(mén)hrowable子類(lèi)。另一個(gè)就是重試根源的斷言對(duì)象使用的是doWithRetry的Exception 異常實(shí)例,不符合正常內(nèi)部斷言的返回設(shè)計(jì)。

Spring Retry提倡以注解的方式對(duì)方法進(jìn)行重試,重試邏輯是同步執(zhí)行的,重試的“失敗”針對(duì)的是Throwable,如果你要以返回值的某個(gè)狀態(tài)來(lái)判定是否需要重試,可能只能通過(guò)自己判斷返回值然后顯式拋出異常了。

Spring 對(duì)于Retry的抽象

“抽象”是每個(gè)程序員必備的素質(zhì)。對(duì)于資質(zhì)平平的我來(lái)說(shuō),沒(méi)有比模仿與理解優(yōu)秀源碼更好地進(jìn)步途徑了吧。為此,我將其核心邏輯重寫(xiě)了一遍...下面就看看Spring Retry對(duì)于“重試”的抽象。

Spring retry相關(guān)接口.jpg

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

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

Guava retryer工具與spring-retry類(lèi)似,都是通過(guò)定義重試者角色來(lái)包裝正常邏輯重試,但是Guava retryer有更優(yōu)的策略定義,在支持重試次數(shù)和重試頻度控制基礎(chǔ)上,能夠兼容支持多個(gè)異常或者自定義實(shí)體對(duì)象的重試源定義,讓重試功能有更多的靈活性。Guava Retryer也是線(xiàn)程安全的,入口調(diào)用邏輯采用的是Java.util.concurrent.Callable的call方法,示例代碼如下:

public void uploadOdps(final Map<String, Object> map) { 
    // RetryerBuilder 構(gòu)建重試實(shí)例 retryer,可以設(shè)置重試源且可以支持多個(gè)重試源,可以配置重試次數(shù)或重試超時(shí)時(shí)間,以及可以配置等待時(shí)間間隔 
    Retryer<Boolean> retryer = RetryerBuilder.<Boolean> newBuilder() 
        .retryIfException().//設(shè)置異常重試源 
        retryIfResult(new Predicate<Boolean>() {//設(shè)置自定義段元重試源, 
      @Override 
      public boolean apply(Boolean state) {//特別注意:這個(gè)apply返回true說(shuō)明需要重試,與操作邏輯的語(yǔ)義要區(qū)分 
        return true; 
      } 
    }) 
    .withStopStrategy(StopStrategies.stopAfterAttempt(5))//設(shè)置重試5次,同樣可以設(shè)置重試超時(shí)時(shí)間 
    .withWaitStrategy(WaitStrategies.fixedWait(100L, TimeUnit.MILLISECONDS)).build();//設(shè)置每次重試間隔 
 
    try { 
      //重試入口采用call方法,用的是java.util.concurrent.Callable<V>的call方法,所以執(zhí)行是線(xiàn)程安全的 
      boolean result = retryer.call(new Callable<Boolean>() {  
        @Override 
        public Boolean call() throws Exception { 
          try { 
            //特別注意:返回false說(shuō)明無(wú)需重試,返回true說(shuō)明需要繼續(xù)重試 
            return uploadToOdps(map); 
          } catch (Exception e) { 
            throw new Exception(e); 
          } 
        } 
      }); 
 
    } catch (ExecutionException e) { 
    } catch (RetryException ex) { 
    } 
  } 

示例代碼原理分析:

RetryerBuilder是一個(gè)factory創(chuàng)建者,可以定制設(shè)置重試源且可以支持多個(gè)重試源,可以配置重試次數(shù)或重試超時(shí)時(shí)間,以及可以配置等待時(shí)間間隔,創(chuàng)建重試者Retryer實(shí)例。

RetryerBuilder的重試源支持Exception異常對(duì)象 和自定義斷言對(duì)象,通過(guò)retryIfException 和retryIfResult設(shè)置,同時(shí)支持多個(gè)且能兼容。

RetryerBuilder的等待時(shí)間和重試限制配置采用不同的策略類(lèi)實(shí)現(xiàn),同時(shí)對(duì)于等待時(shí)間特征可以支持無(wú)間隔和固定間隔方式。

Retryer 是重試者實(shí)例,通過(guò)call方法執(zhí)行操作邏輯,同時(shí)封裝重試源操作。

優(yōu)雅重試共性和原理

正常和重試優(yōu)雅解耦,重試斷言條件實(shí)例或邏輯異常實(shí)例是兩者溝通的媒介。
約定重試間隔,差異性重試策略,設(shè)置重試超時(shí)時(shí)間,進(jìn)一步保證重試有效性以及重試流程穩(wěn)定性。
都使用了命令設(shè)計(jì)模式,通過(guò)委托重試對(duì)象完成相應(yīng)的邏輯操作,同時(shí)內(nèi)部封裝實(shí)現(xiàn)重試邏輯。
Spring-tryer和guava-tryer工具都是線(xiàn)程安全的重試,能夠支持并發(fā)業(yè)務(wù)場(chǎng)景的重試邏輯正確性。

優(yōu)雅重試適用場(chǎng)景

功能邏輯中存在不穩(wěn)定依賴(lài)場(chǎng)景,需要使用重試獲取預(yù)期結(jié)果或者嘗試重新執(zhí)行邏輯不立即結(jié)束。比如遠(yuǎn)程接口訪問(wèn),數(shù)據(jù)加載訪問(wèn),數(shù)據(jù)上傳校驗(yàn)等等。
對(duì)于異常場(chǎng)景存在需要重試場(chǎng)景,同時(shí)希望把正常邏輯和重試邏輯解耦。
對(duì)于需要基于數(shù)據(jù)媒介交互,希望通過(guò)重試輪詢(xún)檢測(cè)執(zhí)行邏輯場(chǎng)景也可以考慮重試方案。

總結(jié)

以上就是本文關(guān)于Java編程Retry重試機(jī)制實(shí)例詳解的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專(zhuān)題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

相關(guān)文章

  • Mybatis注解增刪改查的實(shí)例代碼

    Mybatis注解增刪改查的實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于Mybatis注解增刪改查的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 一文帶你了解Spring中存入Bean和獲取Bean的方式

    一文帶你了解Spring中存入Bean和獲取Bean的方式

    這篇文章主要帶大家了解Spring中存入Bean和獲取Bean的方式,文中的代碼示例講解的非常詳細(xì),對(duì)我們的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-07-07
  • Java中Shiro安全框架的權(quán)限管理

    Java中Shiro安全框架的權(quán)限管理

    這篇文章主要介紹了Java中Shiro安全框架的權(quán)限管理,Apache?Shiro是Java的一個(gè)安全框架,Shiro可以非常容易的開(kāi)發(fā)出足夠好的應(yīng)用,其不僅可以用在JavaSE環(huán)境,也可以用在JavaEE環(huán)境,需要的朋友可以參考下
    2023-08-08
  • java實(shí)現(xiàn)肯德基收銀系統(tǒng)

    java實(shí)現(xiàn)肯德基收銀系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)肯德基收銀系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • Spring中的Filter過(guò)濾器詳解

    Spring中的Filter過(guò)濾器詳解

    這篇文章主要介紹了Spring中的Filter過(guò)濾器詳解,Filter 程序是一個(gè)實(shí)現(xiàn)了特殊接口的 Java 類(lèi),與 Servlet 類(lèi)似,也是由 Servlet 容器進(jìn)行調(diào)用和執(zhí)行的,需要的朋友可以參考下
    2023-08-08
  • 利用Java快速查找21位花朵數(shù)示例代碼

    利用Java快速查找21位花朵數(shù)示例代碼

    這篇文章主要給大家介紹了關(guān)于利用Java快速查找21位花朵數(shù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10
  • Java ThreadLocal詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java ThreadLocal詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    ThreadLocal,很多地方叫做線(xiàn)程本地變量,也有些地方叫做線(xiàn)程本地存儲(chǔ),本文會(huì)詳細(xì)的介紹一下,有興趣的可以了解一下
    2017-06-06
  • Tomcat啟動(dòng)分析(我們?yōu)槭裁匆渲肅ATALINA_HOME環(huán)境變量)

    Tomcat啟動(dòng)分析(我們?yōu)槭裁匆渲肅ATALINA_HOME環(huán)境變量)

    本文主要介紹Tomcat啟動(dòng)分析的知識(shí),這里整理了相關(guān)資料及分析原因和如何實(shí)現(xiàn)的方法,有興趣的小伙伴可以參考下
    2016-09-09
  • java實(shí)現(xiàn)監(jiān)控rtsp流轉(zhuǎn)flv方法實(shí)例(前端播放,前后端代碼都有)

    java實(shí)現(xiàn)監(jiān)控rtsp流轉(zhuǎn)flv方法實(shí)例(前端播放,前后端代碼都有)

    這篇文章主要給大家介紹了關(guān)于java實(shí)現(xiàn)監(jiān)控rtsp流轉(zhuǎn)flv的相關(guān)資料,文中介紹的是前端播放,前后端代碼都有,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • Fluent Mybatis學(xué)習(xí)之Update語(yǔ)法實(shí)踐

    Fluent Mybatis學(xué)習(xí)之Update語(yǔ)法實(shí)踐

    Fluent MyBatis是一個(gè)MyBatis的增強(qiáng)工具,沒(méi)有對(duì)mybatis做任何修改。本篇文章將詳細(xì)介紹對(duì)Fluent Mybatis中的update語(yǔ)法進(jìn)行驗(yàn)證。代碼具有一定價(jià)值,感興趣的小伙伴可以學(xué)習(xí)一下
    2021-11-11

最新評(píng)論