- 1 guava-retry的简介
- 2 guava-retry的使用
- 1 导入maven依赖
- 2 添加一个重试方法
- 3 添加测试类
- 3 总结
官网地址:
https://github.com/rholder/guava-retrying
https://codechina.csdn.net/mirrors/rholder/guava-retrying?utm_source=csdn_github_accelerator
1 guava-retry的简介在日常的一些场景中, 很多需要进行重试的操作.查询资料Guava-Retry工具对于重试操作效果比较好.
Guava retryer是一个基于Guava,提供重试机制的库,是通过定义重试者角色来包装正常逻辑重试,支持重试次数和重试频度控制,能够兼容支持多个异常或者自定义实体对象的重试源定义,让重试功能有更多的灵活性, 而且也是线程安全的,入口调用逻辑采用的是java.util.concurrent.Callable的call方法.
2 guava-retry的使用 1 导入maven依赖
com.github.rholder
guava-retrying
2.0.0
2 添加一个重试方法
@Slf4j
public class RetryDemo {
public static boolean retryMethod(Integer param) {
int i = new Random().nextInt(param);
log.info("随机生成的数:{}", i);
if (1 == i) {
log.info("为1,返回true.");
return true;
} else if (i < 1) {
log.info("小于1,抛出参数异常.");
throw new IllegalArgumentException("参数异常");
} else if (i > 1 && i < 10) {
log.info("大于1,小于10,抛出参数异常.");
return false;
} else {
//为其他
log.info("大于10,抛出自定义异常.");
throw new RemoteAccessException("大于10,抛出自定义异常");
}
}
}
3 添加测试类
@Slf4j
public class GuavaRetryTest {
public static void main(String[] args) {
Boolean result = false;
// RetryerBuilder 构建重试实例对象
// 1 可以设置重试源且可以支持多个重试源
// 2 可以设置根据结果重试
// 3 可以配置等待时间间隔
// 4 可以配置重试次数或重试超时时间
Retryer retryer = RetryerBuilder.newBuilder()
.retryIfExceptionOfType(RemoteAccessException.class)//设置异常重试源
.retryIfException()
.retryIfResult(res -> false) //设置根据结果重试
.withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS)) //设置等待间隔时间
.withStopStrategy(StopStrategies.stopAfterAttempt(3)) //设置最大重试次数
.withRetryListener(new RetryListener() {
@Override
public void onRetry(Attempt attempt) {
log.info("第【{}】次调用失败", attempt.getAttemptNumber());
}
})
.build();
try {
result = retryer.call(new Callable() {
@Override
public Boolean call() throws Exception {
return RetryDemo.retryMethod(110);
}
});
// 上述可以简化为
// result = retryer.call(() -> RetryDemo.retryMethod(110));
} catch (Exception e) {
e.printStackTrace();
log.info("超时三次错误,{}", e.getMessage());
}
System.out.println("方法调用返回状态= " + result);
}
}
说明:
RetryerBuilder类是一个工厂建造者,可以设置多个重试源,可以设置重试次数和重试超时时间等,创建重试者Retryer对象.
RetryerBuilder部分源码:
public class RetryerBuilder{ // 单次任务执行时间限制 private AttemptTimeLimiter attemptTimeLimiter; // 停止策略 private StopStrategy stopStrategy; // 等待策略 private WaitStrategy waitStrategy; // 阻塞策略 private BlockStrategy blockStrategy; // 重试源 支持Exception异常对象和自定义断言对象 private Predicate > rejectionPredicate = Predicates.alwaysFalse(); // 重试监听 private List listeners = new ArrayList (); private RetryerBuilder() { } // new一个RetryerBuilder对象 public static RetryerBuilder newBuilder() { return new RetryerBuilder (); } // 创建一个Retryer对象 public Retryer build() { AttemptTimeLimiter theAttemptTimeLimiter = attemptTimeLimiter == null ? AttemptTimeLimiters. noTimeLimit() : attemptTimeLimiter; StopStrategy theStopStrategy = stopStrategy == null ? StopStrategies.neverStop() : stopStrategy; WaitStrategy theWaitStrategy = waitStrategy == null ? WaitStrategies.noWait() : waitStrategy; BlockStrategy theBlockStrategy = blockStrategy == null ? BlockStrategies.threadSleepStrategy() : blockStrategy; return new Retryer (theAttemptTimeLimiter, theStopStrategy, theWaitStrategy, theBlockStrategy, rejectionPredicate, listeners); } // ... }
Retryer部分源码:
public final class Retryer3 总结{ // 停止策略 private final StopStrategy stopStrategy; // 等待策略 private final WaitStrategy waitStrategy; // 阻塞策略 private final BlockStrategy blockStrategy; // 单次任务执行时间限制 private final AttemptTimeLimiter attemptTimeLimiter; // 重试源 支持Exception异常对象和自定义断言对象 private final Predicate > rejectionPredicate; // 重试监听 private final Collection listeners; // RetryerBuilder建造者中build方法被使用 @Beta public Retryer(@Nonnull AttemptTimeLimiter attemptTimeLimiter, @Nonnull StopStrategy stopStrategy, @Nonnull WaitStrategy waitStrategy, @Nonnull BlockStrategy blockStrategy, @Nonnull Predicate > rejectionPredicate, @Nonnull Collection listeners) { Preconditions.checkNotNull(attemptTimeLimiter, "timeLimiter may not be null"); Preconditions.checkNotNull(stopStrategy, "stopStrategy may not be null"); Preconditions.checkNotNull(waitStrategy, "waitStrategy may not be null"); Preconditions.checkNotNull(blockStrategy, "blockStrategy may not be null"); Preconditions.checkNotNull(rejectionPredicate, "rejectionPredicate may not be null"); Preconditions.checkNotNull(listeners, "listeners may not null"); this.attemptTimeLimiter = attemptTimeLimiter; this.stopStrategy = stopStrategy; this.waitStrategy = waitStrategy; this.blockStrategy = blockStrategy; this.rejectionPredicate = rejectionPredicate; this.listeners = listeners; } // 线程安全调用重试方法 public V call(Callable callable) throws ExecutionException, RetryException { long startTime = System.nanoTime(); for (int attemptNumber = 1; ; attemptNumber++) { Attempt attempt; try { V result = attemptTimeLimiter.call(callable); attempt = new ResultAttempt (result, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); } catch (Throwable t) { attempt = new ExceptionAttempt (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); } } } } }
Guava-Retry, 是一个非常灵活简单上手的工具. 可以完好的把重试功能和业务逻辑解耦, 不但支持多种设置, 如多异常判断,重试次数,重试时间,以及每次重试方法时的监听.并且是属于线程安全的, 在并发的场景下也能稳定支持.
参考资料:
https://blog.csdn.net/zzzgd_666/article/details/84377962



