官網:https://github.com/rholder/guava-retryinghtml
Maven:https://mvnrepository.com/artifact/com.github.rholder/guava-retryingjava
下面示例是基於Spring Boot的,可是均可以用於Spring項目。目前最新版是2.0.0。git
集成步驟:github
POM引入:web
<!-- https://mvnrepository.com/artifact/com.github.rholder/guava-retrying --> <dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency>
直接一個類裏面進行操做,基於匿名內部類實現。spring
package com.jsoft.springboottest.springboottest1.controller; import java.io.IOException; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.github.rholder.retry.RetryException; import com.github.rholder.retry.Retryer; import com.github.rholder.retry.RetryerBuilder; import com.github.rholder.retry.StopStrategies; import com.github.rholder.retry.WaitStrategies; import com.google.common.base.Predicates; @RestController public class TestController { private static final Logger logger = LoggerFactory.getLogger(TestController.class); @RequestMapping("/show") public String show(){ Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder() .retryIfResult(Predicates.<Boolean>isNull())// 設置自定義段元重試源 .retryIfExceptionOfType(Exception.class)// 設置異常重試源 .retryIfRuntimeException()// 設置異常重試源 .withStopStrategy(StopStrategies.stopAfterAttempt(5))// 設置重試5次,一樣能夠設置重試超時時間 .withWaitStrategy(WaitStrategies.fixedWait(5L, TimeUnit.SECONDS))// 設置每次重試間隔,5秒 .build(); try { retryer.call(new Callable<Boolean>() { int i = 0; @Override public Boolean call() throws Exception { i++; logger.info("第{}次執行!", i); // do something if (i<6) {// 模擬錯2次 logger.info("模擬執行失敗!"); throw new IOException("異常"); } logger.info("模擬執行成功!"); return true; } }); } catch (RetryException e) { logger.info("超太重試次數", e); } catch (ExecutionException e) { logger.info("重試框架異常", e); } return "Hello World"; } }
示例工程:https://github.com/easonjim/5_java_example/tree/master/springboottest/springboottest5segmentfault
詳細介紹:springboot
使用場景網絡
在平常開發中,咱們常常會遇到須要調用外部服務和接口的場景。外部服務對於調用者來講通常都是不可靠的,尤爲是在網絡環境比較差的狀況下,網絡抖動很容易致使請求超時等異常狀況,這時候就須要使用失敗重試策略從新調用 API 接口來獲取。重試策略在服務治理方面也有很普遍的使用,經過定時檢測,來查看服務是否存活(Active)。app
Guava Retrying是一個靈活方便的重試組件,包含了多種的重試策略,並且擴展起來很是容易。
用做者的話來講:
This is a small extension to Google’s Guava library to allow for the creation of configurable retrying strategies for an arbitrary function call, such as something that talks to a remote service with flaky uptime.
使用Guava-retrying你能夠自定義來執行重試,同時也能夠監控每次重試的結果和行爲,最重要的基於 Guava 風格的重試方式真的很方便。
代碼示例
如下會簡單列出guava-retrying
的使用方式:
若是拋出IOException
則重試,若是返回結果爲null
或者等於2則重試,固定等待時長爲300 ms,最多嘗試3次;
Callable<Integer> task = new Callable<Integer>() { @Override public Integer call() throws Exception { return 2; } }; Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder() .retryIfResult(Predicates.<Integer>isNull()) .retryIfResult(Predicates.equalTo(2)) .retryIfExceptionOfType(IOException.class) .withStopStrategy(StopStrategies.stopAfterAttempt(3)) .withWaitStrategy(WaitStrategies.fixedWait(300, TimeUnit.MILLISECONDS)) .build(); try { retryer.call(task); } catch (ExecutionException e) { e.printStackTrace(); } catch (RetryException e) { e.printStackTrace(); }
出現異常則執行重試,每次任務執行最長執行時間限定爲 3 s,重試間隔時間初始爲 3 s,最多重試 1 分鐘,隨着重試次數的增長每次遞增 1 s,每次重試失敗,打印日誌;
@Override public Integer call() throws Exception { return 2; } }; Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder() .retryIfException() .withStopStrategy(StopStrategies.stopAfterDelay(30,TimeUnit.SECONDS)) .withWaitStrategy(WaitStrategies.incrementingWait(3, TimeUnit.SECONDS,1,TimeUnit.SECONDS)) .withAttemptTimeLimiter(AttemptTimeLimiters.<Integer>fixedTimeLimit(3,TimeUnit.SECONDS)) .withRetryListener(new RetryListener() { @Override public <V> void onRetry(Attempt<V> attempt) { if (attempt.hasException()){ attempt.getExceptionCause().printStackTrace(); } } }) .build(); try { retryer.call(task); } catch (ExecutionException e) { e.printStackTrace(); } catch (RetryException e) { e.printStackTrace(); }
核心執行邏輯分析:
long startTime = System.nanoTime(); for (int attemptNumber = 1; ; attemptNumber++) { Attempt<V> attempt; try { // 執行成功 V result = attemptTimeLimiter.call(callable); attempt = new ResultAttempt<V>(result, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); } catch (Throwable t) { // 執行失敗 attempt = new ExceptionAttempt<V>(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); } // 監聽器處理 for (RetryListener listener : listeners) { listener.onRetry(attempt); } // 是否符合終止策略 if (!rejectionPredicate.apply(attempt)) { return attempt.get(); } // 是否符合中止策略 if (stopStrategy.shouldStop(attempt)) { throw new RetryException(attemptNumber, attempt); } else { // 計算下次重試間隔時間 long sleepTime = waitStrategy.computeSleepTime(attempt); try { blockStrategy.block(sleepTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RetryException(attemptNumber, attempt); } } }
依賴引入
<dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency>
主要接口及策略介紹:
Attempt
:一次執行任務;
AttemptTimeLimiter
:單次任務執行時間限制(若是單次任務執行超時,則終止執行當前任務);
BlockStrategies
:任務阻塞策略(通俗的講就是當前任務執行完,下次任務還沒開始這段時間作什麼……),默認策略爲:BlockStrategies.THREAD_SLEEP_STRATEGY
也就是調用 Thread.sleep(sleepTime)
;
RetryException
:重試異常;
RetryListener
:自定義重試監聽器,能夠用於異步記錄錯誤日誌;
StopStrategy
:中止重試策略,提供三種:
StopAfterDelayStrategy
:設定一個最長容許的執行時間;好比設定最長執行10s,不管任務執行次數,只要重試的時候超出了最長時間,則任務終止,並返回重試異常RetryException
;NeverStopStrategy
:不中止,用於須要一直輪訓知道返回指望結果的狀況;StopAfterAttemptStrategy
:設定最大重試次數,若是超出最大重試次數則中止重試,並返回重試異常;WaitStrategy
:等待時長策略(控制時間間隔),返回結果爲下次執行時長:
FixedWaitStrategy
:固定等待時長策略;RandomWaitStrategy
:隨機等待時長策略(能夠提供一個最小和最大時長,等待時長爲其區間隨機值)IncrementingWaitStrategy
:遞增等待時長策略(提供一個初始值和步長,等待時間隨重試次數增長而增長)ExponentialWaitStrategy
:指數等待時長策略;FibonacciWaitStrategy
:Fibonacci 等待時長策略;ExceptionWaitStrategy
:異常時長等待策略;CompositeWaitStrategy
:複合時長等待策略;
參考:
http://blog.csdn.net/aitangyong/article/details/53894997
http://www.javashuo.com/article/p-ggbrwvbr-da.html
http://blog.csdn.net/aitangyong/article/details/53886293
http://baijiahao.baidu.com/s?id=1575327487081031&wfr=spider&for=pc
http://www.cnblogs.com/jianzh5/p/6651799.html
http://lintrip.com/2016/05/27/guava-retry/(以上部份內容轉自此篇文章)