在Web应用中,由于网络原因或其他不可预知的原因,应用之间的调用可能会失败。通过配置重试策略,可以有效解决外部原因导致的系统故障。使用场景中微服务之间各个服务模块之间的调用。第三方模块远程交易调用。非业务异常会导致可能的故障。ExamplebuildRetryerprivateRetryerretryer=RetryerBuilder.newBuilder().retryIfException()//Retryonexception.retryIfResult(input->input!=null&&instanceofBoolean&&!Boolean.valueOf((Boolean)input))//返回重试当值为false//对应Future获取超时time.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(4,TimeUnit.SECONDS,Executors.newFixedThreadPool(2)))//重试limit.withRetryListener(newRetryListener(){//重试执行逻辑@OverridepublicvoidonRetry(Attemptattempt){log.info("onRetry->重试次数:{},距离第一次重试时间:{}",attempt.getAttemptNumber(),attempt.getDelaySinceFirstAttempt());if(attempt.hasException()){//异常是否导致重试Throwableexception=attempt.getExceptionCause();//执行异常log.info("Exception:{}",exception);}if(attempt.hasResult()){//是否返回Vresult=attempt.得到结果();log.info("返回:{}",结果);}}})//控制每次重试的间隔,如果AttemptTimeLimiter设置为multi-thread.withWaitStrategy(WaitStrategies.fixedWait(3,TimeUnit.SECONDS))//等待策略.withBlockStrategy(BlockStrategies.threadSleepStrategy())//阻塞策略//.withStopStrategy(StopStrategies.stopAfterAttempt(5))//停止strategy.build();使用Retryer让业务代码具备重试能力前两个如果模拟第一次执行返回false,会执行一次重试;第三次,业务代码正常执行,返回true结束重试@TestpublicvoidretryWhenResult()throwsExecutionException,RetryException{retryer.call(()->{if(counter.incrementAndGet()==3){//前2次模拟返回false,触发重试log.info("执行业务代码:{}次",counter.get());returntrue;}returnfalse;});}如果有前3次模拟出现异常,将执行重试;第三次时,业务代码正常执行,重试结束。@TestpublicvoidretryWhenException()throwsExecutionException,RetryException{retryer.call(()->{if(counter.getAndIncrement()==3){//模拟前5次异常,触发重试返回计数器;}log.info("执行业务代码:{}次",counter.get());thrownewRuntimeException("ERROR");});}前5次模拟存在异常。由于Retryer配置的重试次数为5次,所以最终业务代码不会执行。@TestpublicvoidretryWhenResultOnFailure()throwsExecutionException,RetryException{retryer.call(()->{if(counter.incrementAndGet()==8){//前7次模拟返回false,因为配置重试了5次,所以finalFailedlog.info("执行业务代码:{}次",counter.get());returntrue;}returnfalse;});}执行流程执行流程通过RetryerBuilder构建Retryer,调用Retryer#call,为其回调函数封装业务代码。开始循环执行。回调函数由AttemptTimeLimiter#call执行。将结果封装为Attempt,包括ResultAttempt和ExceptionAttempt两种类型。如果成功,记录执行结果和持续时间;如果失败,记录异常和持续时间。执行监听RetyrListener#onRetry,可以配置多个监听。执行拒绝断言Predicate,根据返回值、执行异常、返回异常类型判断是否终止重试。如果满足条件,则继续重试;否则,结束重试并返回包含回调结果的Attempt。根据终止策略StopStrategy判断是否终止重试。根据等待策略WaitStrategy获取等待时间。根据阻塞策略BlockStrategy和上一步的等待时间阻塞重试,如果出现异常则抛出RetryException。重复上面的逻辑。Retryer的配置构建主要通过RetryerBuilder.newBuilder()实现,其相关配置如下:配置策略名称描述AttemptTimeLimiters任务执行时限NoAttemptTimeLimit无时限FixedAttemptTimeLimit固定时限WaitStrategies重试等待策略ExponentialWaitStrategy索引等待策略增加重试按指数间隔时间,比如第一次2^1100,2^2100,2^3*100...最多300000FibonacciWaitStrategy斐波纳奇等待策略1100,1100,2100,3100,5*100...FixedWaitStrategy固定期限根据配置的等待策略固定间隔时间RandomWaitStrategy随机时长等待策略随机间隔时间,可设置随机取值范围IncrementingWaitStrategy递增等待策略根据配置的初始值累加时间并递增ExceptionWaitStrategy异常等待策略根据异常类型指定等待时间CombinBlockStrategies阻塞策略根据WaitStrategiesThreadSleepStrategy线程等策略通过Thread.sleet()获取阻塞时长实现StopStrategies重试停止策略NeverStopStrategy无限策略StopAfterAttemptStrategy有限次数策略StopAfterDelayStrategy限时策略NoAttemptTimeLimit有限次数注意看onTimeFixedAttempt中的AttemptTimeLimiter是基于guava中的SimpleTimeLimiter,但是在guava的高版本中这个类变成了私有类。综上所述,GuavaRetrying模块可以通过简单的代码实现重试业务逻辑的功能,其配置包括重试次数、时长控制、重试阻塞、终止策略等,在项目技术中非常常用。