通常我们在访问第三方接口时,由于网络抖动或其他原因需要重试,spring和guava都提供了retry的工具。下面简单介绍一下guava的retry,相比较spring的retry,使用起来更加的简单便捷。
首先我们需要实例化一个重试器
eg:
/**
* 创建一个重试器,重试器执行的方法
*/
private static Retryer retryer = RetryerBuilder.newBuilder()
// 出现异常时,会重试
.retryIfException()
// 失败后,隔2秒后重试
.withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
// 重试3次后,仍未成功,就不再重试
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.build();
通过构造方法即可看出各参数的含义。
/**
* Constructor
*
* @param stopStrategy the strategy used to decide when the retryer must stop retrying
* @param waitStrategy the strategy used to decide how much time to sleep between attempts
* @param rejectionPredicate the predicate used to decide if the attempt must be rejected
* or not. If an attempt is rejected, the retryer will retry the call, unless the stop
* strategy indicates otherwise or the thread is interrupted.
*/
public Retryer(@Nonnull StopStrategy stopStrategy,
@Nonnull WaitStrategy waitStrategy,
@Nonnull Predicate<Attempt<V>> rejectionPredicate) {
this(AttemptTimeLimiters.<V>noTimeLimit(), stopStrategy, waitStrategy, BlockStrategies.threadSleepStrategy(), rejectionPredicate);
}
然后使用时,直接通过retryer.call(() -> //TODO业务逻辑)即可。
/**
* Executes the given callable. If the rejection predicate
* accepts the attempt, the stop strategy is used to decide if a new attempt
* must be made. Then the wait strategy is used to decide how much time to sleep
* and a new attempt is made.
*
* @param callable the callable task to be executed
* @return the computed result of the given callable
* @throws ExecutionException if the given callable throws an exception, and the
* rejection predicate considers the attempt as successful. The original exception
* is wrapped into an ExecutionException.
* @throws RetryException if all the attempts failed before the stop strategy decided
* to abort, or the thread was interrupted. Note that if the thread is interrupted,
* this exception is thrown and the thread's interrupt status is set.
*/
public V call(Callable<V> callable) throws ExecutionException, RetryException {
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);
}
}
}
}
使用起来非常的简单,参照着就可以很容易实现一个重试的功能。