前言
目前最流行的二大重试框架,其中一个是spring-retry,另一个就是谷歌的guava-retrying。
Guava retryer工具与spring-retry类似,Guava Retryer也是线程安全的。但是Guava retryer有更优的策略定义,在支持重试次数和重试频度的基础上,还支持特定异常时触发重试 和 callable自定义返回值来判断是否需要重试,让重试功能有更多的灵活性。
第一步:创建SpringBoot项目,添加依赖
<!-- guava-retrying重试框架-->
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
<!-- 用到了slf4j打印日志-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
<!-- 使用了单元测试类-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
第二步:使用匿名内部类创建Callable对象,里面写你要重试的业务
- 实现Callable接口中的call()方法,里面写你要重试的内容——这个就是你的核心业务方法
- <Integer>是返回值类型
//1.具体要做的任务
private Callable<Integer> GeneratNumberCallable() {
return new Callable<Integer>() {
public Integer call() throws Exception {
int number = new Random().nextInt(11);
//随机生成一个0-10的数字
Integer nextInt = new Integer(number);
log.info("随机生成一个数字:{}", nextInt);
return nextInt;
}
};
}
第三步:new一个重试器对象
- 根据你自己的情况选用!!!重试器里面有很多方法,比如设置重试的条件,重试的次数等等。
- 监听器是看你需求,可以监听到重试器的各种状态,比如到现在一共重试了多少次,花了多少时间,callable里面执行时是否出现了异常,callable返回值是多少等等,都可以监听到。具体看下面的案例。
//获得一个重试器对象
public static Retryer getRetryer() {
return RetryerBuilder.<Integer>newBuilder()
//见名知其意,根据callable的返回结果决定要不要重试【如果返回结果不是8,就会重试】
.retryIfResult(number -> !number.equals(8))
//出异常会触发重试
.retryIfException()
//等待策略【3s后重试】
.withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))
//停止策略【重试三次】
// .withStopStrategy(StopStrategies.stopAfterAttempt(3))
//重试监听器
.withRetryListener(new GuavaRetryListener())
.build();
}
第四步:自定义监听器(可选)
- 实现RetryListener接口中的onRetry()方法,attempt对象可以获取重试器的一些属性。具体如下:
getResult()和get():获得callable的返回值 getAttemptNumber():获得已经重试的次数 attempt.hasException()和attempt.getExceptionCause()连用:先判断callable内执行是否出现异常,有才去获取异常 getDelaySinceFirstAttempt():获得从第一次重试到本次重试一共花了多少时间
@Slf4j
public class GuavaRetryListener implements RetryListener {
@Override
public <V> void onRetry(Attempt<V> attempt) {
Throwable exceptionCause = null;
try {
//calable的返回值
V v = attempt.get();
//重试次数
long attemptNumber = attempt.getAttemptNumber();
//获取callable执行时发生的异常
boolean hasException = attempt.hasException();
if (hasException) {
exceptionCause = attempt.getExceptionCause();
}
//获取从第一次重试距离本次重试之间的时间间隔
long delaySinceFirstAttempt = attempt.getDelaySinceFirstAttempt();
//callable返回结果
V result = attempt.getResult();
//输出一下看看
log.info("v:{},exceptionCause:{},attemptNumber:{},b:{},delaySinceFirstAttempt:{},result:{}", v, exceptionCause, attemptNumber, hasException, delaySinceFirstAttempt, result);
} catch (Exception e) {
e.printStackTrace();
}
}
最后:使用重试器和实现你具体业务的callable对象
@Test
void test() throws ExecutionException, RetryException {
//1.拿到重试器
Retryer retryer = getRetryer();
//2.拿到要执行的具体业务【具体业务写在Callable接口里】
Callable<Integer> generatNumberCallable = GeneratNumberCallable();
//3.执行
retryer.call(generatNumberCallable);
}