一.简介
上一篇文章我们介绍了实际项目开发中重试的应用场景,以及spring-retry原理和源码的详细介绍,那么此篇我们将会详细介绍一下另外一个常用的重试组件guava-retrying。 那么guava-retrying是什么?官方的解释是,guava重试模块提供了一个通用方法,用于重试具有特定停止、重试和异常处理功能的任意Java代码,这些功能通过guava的谓词匹配得到了增强。 接下来我们就guava-retrying的使用方式、工作原理以及源码展开介绍和分析。
二.使用方式
1.引入依赖
在项目中引入guava-retrying依赖:
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
复制代码
2.定义方法回调
利用Callable接口定义业务方法回调:
Callable<Boolean> callable = new Callable<Boolean>() {
public Boolean call() throws Exception {
return true; // do something useful here
}
};
复制代码
该回调方法有两个点需要注意,一是返回类型,是根据具体业务场景定义,二是业务逻辑,在call方法中实现自定义重试逻辑实现(调用远程接口或者本地方法)。
3.创建重试器并执行重试
利用RetryerBuilder构建重试器并执行重试逻辑:
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.withRetryListener(new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
log.info("listener receive attempt={}",attempt);
}
})
.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(1, TimeUnit.SECONDS))
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.withWaitStrategy(WaitStrategies.fixedWait(2,TimeUnit.SECONDS))
.withBlockStrategy(BlockStrategies.threadSleepStrategy())
.retryIfException()
.retryIfExceptionOfType(ServiceRuntimeException.class)
.retryIfException(Predicates.equalTo(new Exception()))
.retryIfRuntimeException()
.retryIfResult(Predicates.equalTo(false))
.build();
try {
retryer.call(new callable());
} catch (ExecutionException e) {
log.error("occur error",e);
} catch (RetryException e) {
log.error("occur error",e);
} catch (Exception e) {
log.error("occur error",e);
}
复制代码
我们构建了一个具有最丰富的各种策略的重试器,并执行了重试逻辑。分别包含了重试监听器、重试限制器、终止策略、等待策略、阻塞策略和各种重试策略。这样我们就可以在真实场景中使用guava-retrying提供的重试能力了。
三.原理&源码分析
前边我们介绍了guava-retrying的使用方式,能够看出其使用过程和工作原理就是现根据各种策略构建一个重试器,然后使用重试器调用我们的业务逻辑回调,那么我们将参照源码来逐步分析guava-retrying的工作原理。
1.构造重试器
guava-retrying使用工厂模式创建重试器,入口是RetryerBuilder,我们逐个分析一个各种策略的构建和重试器的构建。
I)监听器
/**
* Adds a listener that will be notified of each attempt that is made
*
* @param listener Listener to add
* @return <code>this</code>
*/
public RetryerBuilder<V> withRetryListener(@Nonnull RetryListener listener) {
Preconditions.checkNotNull(listener, "listener may not be null");
listeners.add(listener);
return this;
}
复制代码
RetryerBuilder.withRetryListener为重试器添加监听器,每次重试的时候将被通知,监听器需实现RetryListener接口,支持多次调用。
II)重试限制器
/**
* Configures the retryer to limit the duration of any particular attempt by the given duration.
*
* @param attemptTimeLimiter to apply to each attempt
* @return <code>this</code>
*/
public RetryerBuilder<V> withAttemptTimeLimiter(@Nonnull AttemptTimeLimiter<V> attemptTimeLimiter) {
Preconditions.checkNotNull(attemptTime