在項目開發中,有的時候,總是避免不了調用第三方服務接口,有的時候可能因為網絡等情況的因素,我們需要重試幾次才能調用成功,所以就需要一重試機制來保證接口的正常訪問。
這是谷歌guava提供的工具包,我們可以在項目中引入相應的包,很輕松實現重試訪問。guava-retrying中大量運用的策略模式,可以自定義各種執行重試策略。下面是簡單實用步驟。
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>19.0</version></dependency><dependency><groupId>com.github.rholder</groupId><artifactId>guava-retrying</artifactId><version>2.0.0</version></dependency>
我這里實現一個對接口的簡單訪問,以此來模擬訪問第三方接口。
@GetMapping("/retrytest")publicMap<String,Object>retrytest(){Map<String,Object>resultMap=Maps.newHashMap();resultMap.put("id",1001L);resultMap.put("msg","測試");Map<String,Object>tokenMap=Maps.newHashMap();tokenMap.put("token",UUID.randomUUID().toString());resultMap.put("data",tokenMap);returnresultMap;}
Retryer中定義重試的各種策略,在執行call方法的時候,會將這些重試策略一一使用。
RetryListener是重試監聽器,可以監聽每次重試的過程。
BlockStrategy是自定義阻塞策略。
@BeanpublicRetryer<String>retry(){RetryListenerretryListener=newRetryListener(){@Overridepublic<V>voidonRetry(Attempt<V>attempt){try{if(attempt.hasException()){log.error("---"+Arrays.toString(attempt.getExceptionCause().getStackTrace()));}else{log.info("---"+attempt.get().toString());}}catch(Exceptione){e.printStackTrace();}}};BlockStrategyblockStrategy=newBlockStrategy(){@Overridepublicvoidblock(longsleepTime)throwsInterruptedException{LocalDateTimestartTime=LocalDateTime.now();longstart=System.currentTimeMillis();longend=start;log.info("[SpinBlockStrategy]...beginwait.");while(end-start<=sleepTime){end=System.currentTimeMillis();}//使用Java8新增的Duration計算時間間隔Durationduration=Duration.between(startTime,LocalDateTime.now());log.info("[SpinBlockStrategy]...endwait.duration={}",duration.toMillis());}};Retryer<String>retryer=RetryerBuilder.<String>newBuilder()//retryIf重試條件.retryIfException().retryIfRuntimeException().retryIfExceptionOfType(Exception.class).retryIfException(Predicates.equalTo(newException()))//等待策略:每次請求間隔1s//.withWaitStrategy(WaitStrategies.fixedWait(1,TimeUnit.SECONDS))//停止策略:嘗試請求3次.withStopStrategy(StopStrategies.stopAfterAttempt(3))//時間限制:某次請求不得超過2s,類似:TimeLimitertimeLimiter=newSimpleTimeLimiter();.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(2,TimeUnit.SECONDS)).withRetryListener(retryListener).withBlockStrategy(blockStrategy).build();returnretryer;}
編寫retryer調用call方法的具體實現邏輯。
@Slf4jpublicclassRetryCallableimplementsCallable<String>{privateRestTemplaterestTemplate;publicRetryCallable(RestTemplaterestTemplate){this.restTemplate=restTemplate;}inttimes=1;@OverridepublicStringcall(){log.info("calltimes={}",times++);log.info("請求時間:{}",LocalDateTime.now());//對遠程地址的訪問returnObjects.requireNonNull(restTemplate.getForObject("http://localhost:8080/retrytest",Object.class)).toString();}}
@GetMapping("/hello")publicObjecthello(@RequestParam(required=false)Stringtoken){log.info("hello"+token);Mapresult=null;Stringmsg="";try{//定義請求實現利用重試器調用請求StringcallResult=retryer.call(newRetryCallable(restTemplate));result=newGson().fromJson(callResult,Map.class);}catch(Exceptione){e.printStackTrace();msg=e.getMessage();log.warn("請求失敗:{}",e.getMessage());}HashMap<String,Object>resultData=Maps.newHashMap();resultData.put("data",result);resultData.put("token",token);resultData.put("msg",msg);returnresultData;}
調用接口測試
2019-10-1213:46:23.863INFO68012---[nio-8080-exec-1]com.wj.retry.controller.HelloController:hellof5b78e95-87f7-435e-b9be-04bcb88ad0562019-10-1213:46:23.865INFO68012---[pool-1-thread-1]com.wj.retry.controller.RetryCallable:calltimes=12019-10-1213:46:23.875INFO68012---[pool-1-thread-1]com.wj.retry.controller.RetryCallable:請求時間:2019-10-12T13:46:23.8742019-10-1213:46:24.068INFO68012---[nio-8080-exec-1]com.wj.retry.RetryApplication:---{msg=測試,data={token=eacb4a99-9ef9-4581-b8e5-28fdabac1c52},id=1001}
若失敗會調用多次(按照重試器中定義的策略)并,拋出異常
上面的實現會寫相對較多的代碼,若使用spring-retry則相對簡單多了,可以基于注解實現
<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId></dependency>
@Retryable的參數說明:
value:拋出指定異常才會重試
include:和value一樣,默認為空,當exclude也為空時,默認所以異常
exclude:指定不處理的異常
maxAttempts:最大重試次數,默認3次
backoff:重試等待策略,默認使用@Backoff,@Backoff的value默認為1000L,我們設置為2000L;multiplier(指定延遲倍數)默認為0,表示固定暫停1秒后進行重試,如果把multiplier設置為1.5,則第一次重試為2秒,第二次為3秒,第三次為4.5秒。
@Retryable(value=Exception.class,maxAttempts=3,backoff=@Backoff(delay=2000L,multiplier=1.5))publicObjectretry(@RequestParam(required=false)Stringtoken){Stringmsg="";log.info("springretry");log.info("請求時間:{}",LocalDateTime.now());StringresultStr=Objects.requireNonNull(restTemplate.getForObject("http://localhost:8080/retrytest",Object.class)).toString();Mapresult=newGson().fromJson(resultStr,Map.class);HashMap<String,Object>resultData=Maps.newHashMap();resultData.put("data",result);resultData.put("token",token);resultData.put("msg",msg);returnresultData;}
最后在啟動類上加上@EnableRetry注解開啟重試機制。ok,就這樣兩個步驟就完成了
除了上面調用第三方服務接口可能會用到重試機制,在微服務項目中,服務之間的通信,重試機制可以說是隨處可見。
在springcloud中Ribbon,feign,Hystrix等組件都可以自己配置重試機制,來達到提高能正常通信的成功率。
此外,在各種消息中間件中也都有重試機制的體現,例如kafka,消息發送失敗可以重新發送,消息消費失敗了,也可以配置重試機制,可以最大程度達到消息的不丟失。
可以考慮這么一個事情,若目標邏輯執行時間過長,超出了重試的等待時間,客戶端就要發起重試,那么服務端就會出現重復調用執行的問題,所以,有重試機制就要考慮冪等性的問題。
到此,關于“Retry重試機制是什么意思”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注本站網站,小編會繼續努力為大家帶來更多實用的文章!
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
c語言中正確的字符常量是用一對單引號將一個字符括起表示合法的字符常量。例如‘a’。數值包括整型、浮點型。整型可用十進制,八進制,十六進制。八進制前面要加0,后面...
2022年天津專場考試原定于3月19日舉行,受疫情影響確定延期,但目前延期后的考試時間推遲。 符合報名條件的考生,須在規定時間登錄招考資訊網(www.zha...
:喜歡聽,樂意看。指很受歡迎?!巴卣官Y料”喜聞樂見:[ xǐ wén lè jiàn ]詳細解釋1. 【解釋】:喜歡聽,樂意看。指很受歡迎。2. 【示例】:這是...
(相關資料圖)關于千金女賊劉愷威唐嫣吻戲在哪一集的知識大家了解嗎?以下就是小編整理的關于千金女賊劉愷威唐嫣吻戲在哪一集的介紹,希望可以給到大家一些參考,一起來了解下吧!1、千金女賊劉愷威唐嫣吻戲是在15集。2、該劇講述了1930年的上海租界,蔣心是即將認親的名門千金,而杜小寒是冒死逃獄的女賊,女賊躍上枝頭變鳳凰,本來的千金,卻碾轉變成白幫幫主白正擎的女人。3、劇中唐嫣飾演蔣心,即將認親的名門千金,...
浙江稠州銀行是私人銀行嗎?浙江稠州銀行不是私人的。浙江稠州商業銀行是一家具有獨立法人資格的股份制商業銀行,成立于1987年6月,是義烏第一家地方性金融機構。其前身為義烏市稠州城市信用合作社。浙江稠州商業銀行曾獲得義烏市的”經濟發展貢獻獎”“綜合實力獎” 等獎項,曾被評為"AAA級納稅信譽企業”浙江稠州商業銀行,其前身為義烏市稠州...
【資料圖】哈嘍小伙伴們 ,今天給大家科普一個小知識。在日常生活中我們或多或少的都會接觸到明朝有朱歷這個皇帝嗎方面的一些說法,有的小伙伴還不是很了解,今天就給大家詳細的介紹一下關于明朝有朱歷這個皇帝嗎的相關內容。明朝皇帝:明太祖朱元璋、明惠帝朱允炆、明成祖朱棣、明仁宗朱高熾、明宣宗朱瞻基、明英宗朱祁鎮、明代宗朱祁鈺、明憲宗朱見深 、明孝宗朱佑樘、明武宗朱厚照、明世宗朱厚熜、明穆宗朱載垕、明神宗朱翊鈞...