Spring错误异常重试框架guava-retrying
官网:https://github.com/rholder/guava-retrying
Maven:https://mvnrepository.com/artifact/com.github.rholder/guava-retrying
下面示例是基于Spring Boot的,但是都可以用于Spring项目。目前最新版是2.0.0。
集成步骤:
POM引入:
<!-- 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>
直接一个类里面进行操作,基于匿名内部类实现。
package com.jsoft.springboottest.springboottest1.controller; import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicates; @RestController
public class TestController { private static final Logger logger = LoggerFactory.getLogger(TestController.class); @RequestMapping("/show")
public String show(){
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfResult(Predicates.<Boolean>isNull())// 设置自定义段元重试源
.retryIfExceptionOfType(Exception.class)// 设置异常重试源
.retryIfRuntimeException()// 设置异常重试源
.withStopStrategy(StopStrategies.stopAfterAttempt(5))// 设置重试5次,同样可以设置重试超时时间
.withWaitStrategy(WaitStrategies.fixedWait(5L, TimeUnit.SECONDS))// 设置每次重试间隔,5秒
.build();
try {
retryer.call(new Callable<Boolean>() {
int i = 0; @Override
public Boolean call() throws Exception {
i++;
logger.info("第{}次执行!", i);
// do something
if (i<6) {// 模拟错2次
logger.info("模拟执行失败!");
throw new IOException("异常");
}
logger.info("模拟执行成功!");
return true;
}
});
} catch (RetryException e) {
logger.info("超过重试次数", e);
} catch (ExecutionException e) {
logger.info("重试框架异常", e);
} return "Hello World";
} }
示例工程:https://github.com/easonjim/5_java_example/tree/master/springboottest/springboottest5
详细介绍:
使用场景
在日常开发中,我们经常会遇到需要调用外部服务和接口的场景。外部服务对于调用者来说一般都是不可靠的,尤其是在网络环境比较差的情况下,网络抖动很容易导致请求超时等异常情况,这时候就需要使用失败重试策略重新调用 API 接口来获取。重试策略在服务治理方面也有很广泛的使用,通过定时检测,来查看服务是否存活(Active)。
Guava Retrying是一个灵活方便的重试组件,包含了多种的重试策略,而且扩展起来非常容易。
用作者的话来说:
This is a small extension to Google’s Guava library to allow for the creation of configurable retrying strategies for an arbitrary function call, such as something that talks to a remote service with flaky uptime.
使用Guava-retrying你可以自定义来执行重试,同时也可以监控每次重试的结果和行为,最重要的基于 Guava 风格的重试方式真的很方便。
代码示例
以下会简单列出guava-retrying的使用方式:
如果抛出IOException则重试,如果返回结果为null或者等于2则重试,固定等待时长为300 ms,最多尝试3次;
Callable<Integer> task = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return 2;
}
};
Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
.retryIfResult(Predicates.<Integer>isNull())
.retryIfResult(Predicates.equalTo(2))
.retryIfExceptionOfType(IOException.class)
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.withWaitStrategy(WaitStrategies.fixedWait(300, TimeUnit.MILLISECONDS))
.build();
try {
retryer.call(task);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
出现异常则执行重试,每次任务执行最长执行时间限定为 3 s,重试间隔时间初始为 3 s,最多重试 1 分钟,随着重试次数的增加每次递增 1 s,每次重试失败,打印日志;
@Override
public Integer call() throws Exception {
return 2;
}
}; Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
.retryIfException()
.withStopStrategy(StopStrategies.stopAfterDelay(30,TimeUnit.SECONDS))
.withWaitStrategy(WaitStrategies.incrementingWait(3, TimeUnit.SECONDS,1,TimeUnit.SECONDS))
.withAttemptTimeLimiter(AttemptTimeLimiters.<Integer>fixedTimeLimit(3,TimeUnit.SECONDS))
.withRetryListener(new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
if (attempt.hasException()){
attempt.getExceptionCause().printStackTrace();
}
}
})
.build();
try {
retryer.call(task);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
核心执行逻辑分析:
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);
}
}
}
依赖引入
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
主要接口及策略介绍:
Attempt:一次执行任务;
AttemptTimeLimiter:单次任务执行时间限制(如果单次任务执行超时,则终止执行当前任务);
BlockStrategies:任务阻塞策略(通俗的讲就是当前任务执行完,下次任务还没开始这段时间做什么……),默认策略为:BlockStrategies.THREAD_SLEEP_STRATEGY 也就是调用 Thread.sleep(sleepTime);
RetryException:重试异常;
RetryListener:自定义重试监听器,可以用于异步记录错误日志;
StopStrategy:停止重试策略,提供三种:
StopAfterDelayStrategy:设定一个最长允许的执行时间;比如设定最长执行10s,无论任务执行次数,只要重试的时候超出了最长时间,则任务终止,并返回重试异常RetryException;NeverStopStrategy:不停止,用于需要一直轮训知道返回期望结果的情况;StopAfterAttemptStrategy:设定最大重试次数,如果超出最大重试次数则停止重试,并返回重试异常;
WaitStrategy:等待时长策略(控制时间间隔),返回结果为下次执行时长:
FixedWaitStrategy:固定等待时长策略;RandomWaitStrategy:随机等待时长策略(可以提供一个最小和最大时长,等待时长为其区间随机值)IncrementingWaitStrategy:递增等待时长策略(提供一个初始值和步长,等待时间随重试次数增加而增加)ExponentialWaitStrategy:指数等待时长策略;FibonacciWaitStrategy:Fibonacci 等待时长策略;ExceptionWaitStrategy:异常时长等待策略;CompositeWaitStrategy:复合时长等待策略;
参考:
http://blog.csdn.net/aitangyong/article/details/53894997
https://segmentfault.com/a/1190000006918410
http://blog.csdn.net/aitangyong/article/details/53886293
http://baijiahao.baidu.com/s?id=1575327487081031&wfr=spider&for=pc
http://www.cnblogs.com/jianzh5/p/6651799.html
http://lintrip.com/2016/05/27/guava-retry/(以上部分内容转自此篇文章)
Spring错误异常重试框架guava-retrying的更多相关文章
- Spring异常重试框架Spring Retry
Spring Retry支持集成到Spring或者Spring Boot项目中,而它支持AOP的切面注入写法,所以在引入时必须引入aspectjweaver.jar包. 快速集成的代码样例: @Con ...
- 异常重试框架Spring Retry实践
前期准备在Maven项目中添加Spring Retry和切面的依赖 POM: <!-- Spring Retry --> <dependency> <groupId> ...
- 更好的 java 重试框架 sisyphus 背后的故事
sisyphus 综合了 spring-retry 和 gauva-retrying 的优势,使用起来也非常灵活. 今天,让我们一起看一下西西弗斯背后的故事. 情景导入 简单的需求 产品经理:实现一个 ...
- spring batch批量处理框架
spring batch精选,一文吃透spring batch批量处理框架 前言碎语 批处理是企业级业务系统不可或缺的一部分,spring batch是一个轻量级的综合性批处理框架,可用于开发企业信息 ...
- 【转】Java异常总结和Spring事务处理异常机制浅析
异常的概念和Java异常体系结构 异常是程序运行过程中出现的错误.本文主要讲授的是Java语言的异常处理.Java语言的异常处理框架,是Java语言健壮性的一个重要体现. Thorwable类所有异常 ...
- Java异常总结和Spring事务处理异常机制浅析
异常的概念和Java异常体系结构 异常是程序运行过程中出现的错误.本文主要讲授的是Java语言的异常处理.Java语言的异常处理框架,是Java语言健壮性的一个重要体现. Thorwable类所有异常 ...
- 错误/异常:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/classes/beans_common.xml]...的解决方法
1.第一个这种类型的异常 1.1.异常信息:org.springframework.beans.factory.BeanCreationException: Error creating bean w ...
- Guava Retrying
目录 依赖 使用demo RetryerBuilder 实现callable接口 调用 git 参考 依赖 <dependency> <groupId>com.github.r ...
- 更好的 java 重试框架 sisyphus 入门简介
What is Sisyphus sisyphus 综合了 spring-retry 和 gauva-retrying 的优势,使用起来也非常灵活. 为什么选择这个名字 我觉得重试做的事情和西西弗斯很 ...
随机推荐
- 在ubuntun虚拟机里安装goLang语言编程环境
Go语言是谷歌2009发布的第二款开源编程语言. Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全.支持并行进程. 北京时间2010年 ...
- JVM_Bind问题的解决方案
心得:删除javaw.exe进程即可. 以下是网络的解决方案: JVM_Bind问题出现通常有两种情况. 一种是原来的javaw.exe没有结束掉而又新创建了一个javaw.exe进程.这本无可厚非, ...
- python struct.pack方法报错argument for 's' must be a bytes object 解决
参考 https://blog.csdn.net/weixin_38383877/article/details/81100192 在python3下使用struct模块代码 fileHead = s ...
- HTTP隧道代理
reGeorg的前身是2008年SensePost在BlackHat USA 2008 的 reDuh延伸与扩展.也是目 前安全从业人员使用最多,范围最广,支持多丰富的一款http隧道.从本质上讲,可 ...
- webpack打包 css文件里面图片路径 替换位置
{ test: /\.css$/, use: ExtractTextPlugin.extract({ use: ['css-loader?minimize', 'autoprefixer-loader ...
- docker 深入理解之cgroups
cgroups 资源限制 cgroups 是什么 cgroups 最初名为process container,有Google工程师Paul Menage和Rohit Seth于 2006 年提出,后由 ...
- 模板引擎freemarker的使用(一)
配置 了解和学习一下freemarker在项目中的配置与使用,顺便记录下来,知识源于分享,进步源于交流... 我是在ssm中配置的. maven 中需要引入的依赖 <!-- freemarker ...
- Vue之computed与watch的使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 如何给run()方法传参数
实现的方式主要有三种 1.构造函数传参 2.成员变量传参 3.回调函数传参 问题:如何实现处理线程的返回值? 1.主线程等待法(优点:实现起来简单,缺点:需要等待的变量一多的话,代码就变的非常臃肿.而 ...
- luogu P1042 乒乓球
题目背景 国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及.其中11分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役.华华就是其中一位,他退役 ...