简介
在项目中, 我们一定会遇到在某一步骤会重试多次, 直到成功, 比如: 爬虫在爬取网页的时候,调用第三方接口的时候。
在必要的地方加上错误重试是很有必要的, 多次重试可以提高程序的健壮性, 减少业务的错误。
一般来说, 我们可能就简单的使用for,while循环多次,直到达到某个条件退出, 还是写的比较简单的。
现在我们就简绍guava-retry, 是由google研发的一款重试工具。
使用
pom.xml
<dependencies>
<!-- https://mvnrepository.com/artifact/com.github.rholder/guava-retrying -->
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
GuavaRetry.java
package top.itkaito.java.tool.t01;
import com.github.rholder.retry.*;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* guava-retry
*/
public class GuavaRetry {
public static void main(String[] args) {
// try{
// sendMsg("hello tom!!!");
// }catch (Throwable t){
// t.printStackTrace();
// }
Retryer<Object> retry = RetryerBuilder.newBuilder()
// 抛异常
.retryIfException()
// 停止策略
.withStopStrategy(StopStrategies.neverStop())
// 重试等待策略
.withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))
// 重试运行时间限制
.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(3, TimeUnit.SECONDS))
// 监听
.withRetryListener(new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
long attemptNumber = attempt.getAttemptNumber();
System.out.println(String.format("第%s次重试", attemptNumber));
}
}).build();
try {
Object call = retry.call(() -> {
sendMsg("hello world!!!");
return true;
});
System.out.println(call);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
}
public static void sendMsg(String msg) {
// 模拟一定几率出错
int i = new Random().nextInt(10);
if (i <= 4) {
throw new RuntimeException("未知情况, 程序出错");
}
if (i <= 7) {
try {
Thread.sleep(10*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(String.format("your msg:%s has send success", msg));
}
}
运行我们发现程序会报错, 详情见下面参考 1
解决方案: 将guava依赖改为19.0版本
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
讲解
RetryBuilder
RetryBuilder用了创建者模式, 用来创建Retryer的。
StopStrategy
停止策略, 在程序运行出现异常后, 是否停止
停止策略 | 值 |
---|---|
StopStrategies.neverStop() | 永不停止 |
StopStrategies.stopAfterAttempt(attemptNumber) | 重试attemptNumber次后停止 |
StopStrategies.stopAfterDelay(duration, timeUnit) | 延迟指定时间后停止 |
WaitStrategy
等待策略, 在程序运行出现异常后, 等下下次重试的策略
停止策略 | 值 |
---|---|
WaitStrategies.noWait() | 不停止, 立即下次重试 |
fixedWait(sleepTime, timeUnit) | 等待指定时间, 再进行下次重试 |
randomWait(..) | 等待随机时间, 再进行下次重试 |
incrementingWait(...) | 每次重试后, 等待的时间会变长 |
exponentialWait(..) | 等待时间指数级变长?? |
fibonacciWait(...) | 斐波那契变长??? |
AttemptTimeLimiter
重试时间限制, 单词重试允许的时间
重试时间策略 | 值 |
---|---|
AttemptTimeLimiters.noTimeLimit() | 没时间限制 |
fixedTimeLimit(...) | 固定时间限制 |
RetryListener
重试监听器, 每次重试的时候, 会回调该类的onRetry方法