Spring错误异常重试框架guava-retrying
2017-11-01 15:54
585 查看
官网:https://github.com/rholder/guava-retrying
Maven:https://mvnrepository.com/artifact/com.github.rholder/guava-retrying
下面示例是基于Spring Boot的,但是都可以用于Spring项目。目前最新版是2.0.0。
集成步骤:
POM引入:
直接一个类里面进行操作,基于匿名内部类实现。
示例工程: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 风格的重试方式真的很方便。
代码示例
以下会简单列出
如果抛出
出现异常则执行重试,每次任务执行最长执行时间限定为 3 s,重试间隔时间初始为 3 s,最多重试 1 分钟,随着重试次数的增加每次递增 1 s,每次重试失败,打印日志;
核心执行逻辑分析:
依赖引入
参考:
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/(以上部分内容转自此篇文章)
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/(以上部分内容转自此篇文章)
相关文章推荐
- Java异常错误重试方案研究(转)(spring-retry/guava-retryer)
- Spring异常重试框架Spring Retry
- spring boot框架学习9-spring boot的web开发(5)-错误解决及跳转页面
- SSM高级整合_Spring版本异常错误
- spring 框架 service 层 事务异常
- Android开发中调用Spring CXF整合发布的WebService接口为什么抛出异常错误?
- 七牛云 播放的时候显示错误信息:视频解析异常 请重试
- spring+mybatis轻量级企业框架的学习之路之错误笔记day04
- Foundation框架—错误接收与异常处理
- Spring Boot实战之全局异常捕获 实现参数异常检查返回统一错误信息
- spring 验证框架出现错误ValidationMessages not found排查
- [Guava]Throwables:简化异常和错误的传播与检查
- 三大框架开发时,spring配置文件出现异常
- [Google Guava] 1.5-Throwables:简化异常和错误的传播与检查
- 全局异常处理类的定义与错误页面实现(基于SpringBoot)
- spring3+mybatis3框架整合 启动错误记录
- 使用 shiro 框架认证错误,但是控制器未抛出任何异常
- 【框架】[Spring]纯Java方式实现AOP拦截-详解ThrowsAdvice异常通知
- SpringBoot框架中REST接口的异常处理方法
- 使用composer安装第三方错误异常类插件和medoo轻量级数据库框架到框架中