前言

小伙伴是不是经常遇到接口调用异常的情况?

很多小伙伴的实现方式是写个循环调用;

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#333333"><strong>for</strong></span>(<span style="color:#397300">int</span> i= <span style="color:#880000">1</span> ;i<= <span style="color:#880000">3</span> ;i++){<span style="color:#333333"><strong>try</strong></span> {<span style="color:#333333"><strong>if</strong></span> (doExec()){<span style="color:#333333"><strong>break</strong></span> ;}}<span style="color:#333333"><strong>抓</strong></span>{}
}</span></span>

方式是比较简单的,但是非常不灵活,今天出门不能很顾虑,但是这种情况很顾虑。实现给大家带来一个重试重试的组件,流行度很明亮,即是番石榴重试组件。功能强大,是平日旅行的必备工具。

引用

<span style="color:#444444"><span style="background-color:#f6f6f6">< <span style="color:#333333"><strong>dependency</strong></span> > < <span style="color:#333333"><strong>groupId</strong></span> > com.github.rholder </ <span style="color:#333333"><strong>groupId</strong></span> > < <span style="color:#333333"><strong>artifactId</strong></span> > guava- retrying< / <span style="color:#333333"><strong>artifactId</strong></span> > < <span style="color:#333333"><strong>version</strong></span> > 2.0.0 </ <span style="color:#333333"><strong>version</strong></span> >
<span style="color:#888888"><!--修复与guava重复的依赖--> </span>
<span style="color:#888888"><! -- <exclusions>--> </span>
<span style="color:#888888"><!-- <exclusion>--> </span>
<span style="color:#888888"><!-- <groupId>com.google.guava</groupId>--> </span>
<span style="color:#888888"><!-- <artifactId>guava</artifactId>- -> </span>
<span style="color:#888888"><!-- </exclusion>--> </span>
<span style="color:#888888"><!-- <排除>-></span>
<span style="color:#888888"><!-- <groupId>com.google.code.findbugs</groupId>--> </span>
<span style="color:#888888"><!-- <artifactId>jsr305</artifactId>--> </span>
<span style="color:#888888"><!-- </exclusion>--> </span>
<span style="color:#888888"><!- - </exclusions>--> </span>
</<span style="color:#333333"><strong>依赖</strong></span>></span></span>

guava-retrying包中应用有相关的guava版本依赖,如果和自身项目突破可以解决。

示例

执行方法

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#880000"><strong>@Service</strong></span><span style="color:#333333"><strong> public </strong></span><span style="color:#333333"><strong>class</strong></span> RetryService {<span style="color:#333333"><strong>private </strong></span><span style="color:#333333"><strong>static </strong></span><span style="color:#880000">Logger </span><span style="color:#333333"><strong>logger</strong></span> = <span style="color:#880000">LoggerFactory.getLogger</span> ( <span style="color:#880000">RetryService.class</span> ); <span style="color:#880000">_ </span>
<span style="color:#333333"><strong>私有</strong></span><span style="color:#880000">AtomicInteger</span><span style="color:#397300">计数</span>= 新<span style="color:#880000">AtomicInteger</span> ( <span style="color:#880000">0</span> );<span style="color:#333333"><strong>公共</strong></span>int doExec(){       logger.info( <span style="color:#880000">"调用了{}次"</span> , <span style="color:#397300">count</span> .incrementAndGet());<span style="color:#333333"><strong>if</strong></span> ( <span style="color:#397300">count</span> . <span style="color:#333333"><strong>get</strong></span> () % <span style="color:#880000">2</span> == <span style="color:#880000">0</span> ){<span style="color:#333333"><strong>throw</strong></span> new <span style="color:#880000">Exception</span> ( <span style="color:#880000">"----->异常了哦"</span> );}<span style="color:#333333"><strong>返回</strong></span> <span style="color:#397300">计数</span>。<span style="color:#333333"><strong>得到</strong></span>();}
}</span></span>

其中定义了doExec方法,每次调用计数加1,如果是的倍数就抛。

调用方法

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#333333"><strong>公共</strong></span>字符串 test01(){Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder().retryIfRuntimeException()<span style="color:#888888">//retryIfResult 表达式返回true,则重试</span>.retryIfResult(结果 -> {<span style="color:#333333"><strong>如果</strong></span>(结果 % <span style="color:#880000">3</span> == <span style="color:#880000">0</span>){logger.info( <span style="color:#880000">"----->应该试重了"</span> );<span style="color:#333333"><strong>返回</strong></span> <span style="color:#78a960">真</span>;}<span style="color:#333333"><strong>返回</strong></span> <span style="color:#78a960">假</span>;}).withStopStrategy(StopStrategies.stopAfterAttempt( <span style="color:#880000">3</span> ))。建造();<span style="color:#333333"><strong>试试</strong></span>{retryer.call(() -> retryService.doExec());}<span style="color:#333333"><strong>捕捉</strong></span>(ExecutionException e){logger.error( <span style="color:#880000">"异常1:{}"</span> ,e.getMessage());}<span style="color:#333333"><strong>捕捉</strong></span>(重试异常 e){logger.error( <span style="color:#880000">"异常:{}"</span> ,e.getMessage());}<span style="color:#333333"><strong>返回</strong></span> <span style="color:#880000">“确定”</span>;
}</span></span>

从上面代码中,我们就可以实现条件重试。

番石榴的重试思想可分为重试重条件、停试策略、重试间歇策略

一、试重条件

表示在什么情况下,重试。重试组件中的RetryerBuilder的retryIfXXX()方法使用设置在什么情况下进行重试,用户可以在什么情况下根据执行异常进行重试和根据方法执行结果进行重试三个。

可知异常重试

1、retryIfException() 当执行方法抛出异常时重试

2、retryIfRuntimeException()当方法执行抛出异常RuntimeException时重试

3、retryIfExceptionOfType(exceptionClass)当方法执行抛出异常具体哪个异常时重试

4、retryIfException(Predicate p)自定义异常什么情况下重试

可知返回结果重试

retryIfResult(@Nonnull Predicate<V> resultPredicate)根据返回值判断是否重试。

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#888888">//返回真时,重试</span>
.retryIfResult(结果 -> {<span style="color:#333333"><strong>如果</strong></span>(结果 % <span style="color:#880000">3</span> == <span style="color:#880000">0</span>){logger.info( <span style="color:#880000">"----->应该试重了"</span> );<span style="color:#333333"><strong>返回</strong></span> <span style="color:#78a960">真</span>;}<span style="color:#333333"><strong>返回</strong></span> <span style="color:#78a960">假</span>;
})</span></span>

上面的结果代表的是返回值,判断返回值对3取余,返回真实时则进行重试。

二、停止重试策略

重试需要提供停止重试的策略withStopStrategy,简单的方式就是重试次数最多

1、StopAfterAttempt策略

从面字上面就知道什么英文,即在执行次数指定次数之后停止重试。

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#880000">.withStopStrategy</span> ( <span style="color:#333333"><strong>StopStrategies </strong></span><span style="color:#880000">.stopAfterAttempt</span> (3))</span></span>

2、永不停止策略

永远重试,一直重试

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#880000">.withStopStrategy</span> ( <span style="color:#333333"><strong>StopStrategies </strong></span><span style="color:#880000">.neverStop</span> ())</span></span>

3、StopAfterDelay策略

设定一个最长的时间;只要设定一次执行最多执行10s,不计次数,试试的时间与第一次的时间差,最长时间,执行则执行,返回执行重试重试异常

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#880000">.withStopStrategy</span> ( <span style="color:#333333"><strong>StopStrategies </strong></span><span style="color:#880000">.stopAfterDelay</span> (10, <span style="color:#333333"><strong>TimeUnit </strong></span><span style="color:#880000">.SECONDS</span> ))</span></span>

三、重试间隔策略

在重试场景中,我们最好的试试重试的间隔,如果没有间隔,可能有连续的重试失败。

等待策略

1、固定等待策略

固定时长重试间歇。

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#880000">.withWaitStrategy</span> ( <span style="color:#333333"><strong>WaitStrategies </strong></span><span style="color:#880000">.fixedWait</span> (1, <span style="color:#333333"><strong>TimeUnit </strong></span><span style="color:#880000">.SECONDS</span> ))</span></span>

那就是重试间隔为1秒。

2、随机等待策略

随时的间隔时长

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#880000">.withWaitStrategy</span> ( <span style="color:#333333"><strong>WaitStrategies </strong></span><span style="color:#880000">.randomWait</span> (1, <span style="color:#333333"><strong>TimeUnit </strong></span><span style="color:#880000">.SECONDS</span> ,5, <span style="color:#333333"><strong>TimeUnit </strong></span><span style="color:#880000">.SECONDS</span> ))</span></span>

第1个间隔时间长,最小个间隔时间长的时间;每次间隔时间是第二个参数。

3、增量等待策略

递增的间隔时间长,即每次任务重试的时间递增,越来越长

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#880000">.withWaitStrategy</span> ( <span style="color:#333333"><strong>WaitStrategies </strong></span><span style="color:#880000">.incrementingWait</span> (3, <span style="color:#333333"><strong>TimeUnit </strong></span><span style="color:#880000">.SECONDS</span> ,1, <span style="color:#333333"><strong>TimeUnit </strong></span><span style="color:#880000">.SECONDS</span> ))</span></span>

该策略输入一个每隔一段时间的等待时间增加一个步长,然后每次值和时间的长都递增。

4、异常等待策略

根据不同的不同,决定不同的间隔时长。

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#880000">.withWaitStrategy</span> (WaitStrategies.exceptionWait(Exception.class, new Function<Exception, Long>() {<span style="color:#bc6060">@Override</span> public <span style="color:#bc6060">@Nullable</span> Long apply( <span style="color:#bc6060">@Nullable</span>异常输入) {if (input instanceof NullPointerException){返回  <span style="color:#880000">1</span> * <span style="color:#880000">1000</span>升;}else if (input instanceof IndexOutOfBoundsException){返回  <span style="color:#880000">2</span> * <span style="color:#880000">1000</span>升;}else if (input instanceof IllegalStateException){返回  <span style="color:#880000">3</span> * <span style="color:#880000">1000</span>升;}返回<span style="color:#880000">0</span>升;}
}))</span></span>

这个的代码一看就知道了。

是一些常见的策略,不常用的策略,小伙伴们先等待。

我们需要记录一个非常重要的试试机会关注系统的产品。

我们来介绍一下重试监听器。

重试监听器RetryListener

当重试时,会调用RetryListener的onRetry方法,这样我们就可以做一些自定义的重试的额外任务。

定义一个类,继承RetryListener接口

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#333333"><strong>公共</strong></span> <span style="color:#333333"><strong>类</strong></span> <span style="color:#880000"><strong>MyRetryListener</strong></span> <span style="color:#333333"><strong>实现</strong></span> <span style="color:#880000"><strong>RetryListener</strong></span>  {<span style="color:#333333"><strong>私有</strong></span> <span style="color:#333333"><strong>静态</strong></span>Logger logger = LoggerFactory.getLogger(MyRetryListener.class);<span style="color:#1f7199">@Override </span><span style="color:#333333"><strong>public</strong></span> <Integer> <span style="color:#333333"><strong>void </strong></span> <span style="color:#880000"><strong>onRetry </strong></span>(Attempt<Integer> 尝试)  {<span style="color:#333333"><strong>if</strong></span> (attempt.hasResult()){logger.info( <span style="color:#880000">"===> 方法返回的结果:{}"</span> ,attempt.getResult());}<span style="color:#333333"><strong>if</strong></span> (attempt.hasException()){logger.info( <span style="color:#880000">"===>第{}次执行, 异常:{}"</span> ,attempt.getAttemptNumber(),attempt.getExceptionCause()== <span style="color:#333333"><strong>null</strong></span> ? <span style="color:#880000">""</span> : attempt.getExceptionCause().getMessage());<span style="color:#333333"><strong>返回</strong></span>;}logger.info( <span style="color:#880000">"===>第{}次执行"</span> ,attempt.getAttemptNumber());}
}</span></span>

在RetryerBuilder中加入;

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#880000">.withRetryListener</span> (new MyRetryListener())</span></span>

这样就实现了监听业务

重试原理

guava-retrying的组件功能还是比较强大的,我们可以看看内核的代码

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#333333"><strong>public</strong></span> V <span style="color:#333333"><strong>call</strong></span> (Callable<V> callable) <span style="color:#333333"><strong>throws</strong></span> ExecutionException, RetryException {<span style="color:#333333"><strong>long</strong></span> startTime = System.nanoTime();<span style="color:#888888">// 执行次数从</span><span style="color:#333333"><strong>1Startfor</strong></span> ( <span style="color:#333333"><strong>int</strong></span> attemptNumber = <span style="color:#880000">1</span> ; ; attemptNumber++) {尝试<V>尝试;<span style="color:#333333"><strong>try</strong></span> {<span style="color:#888888">//</span>尝试执行V result = attemptTimeLimiter. <span style="color:#333333"><strong>调用</strong></span>(可调用);<span style="color:#888888">// 执行成功则将结果封装为ResultAttempt</span> attempt = <span style="color:#333333"><strong>Retryer.ResultAttempt</strong></span> <V>(result, tryNumberlis(System.nanoTime() - startTime));} <span style="color:#333333"><strong>catch</strong></span> ( <span style="color:#888888">Thrable t) { // 执行异常则将封装</span><span style="color:#333333"><strong>结果</strong></span>为ExceptionAttempt}<span style="color:#888888">// 这里将执行结果传给RetryListener 做一些额外的事情</span><span style="color:#333333"><strong>for</strong></span> (RetryListener listener : listeners) {listener.onRetry(尝试);}<span style="color:#888888">//这个就是决定是否要进行重试的地方,如果不进行重试直接返回结果,执行成功就返回结果,执行失败就返回异常</span><span style="color:#333333"><strong>if</strong></span> (!rejectionPredicate.apply(attempt)) {<span style="color:#333333"><strong>return</strong></span> attempt.get() ;}<span style="color:#888888">// 到这里,说明需要重试,此时先决定是否达到异常则停止重试的时机,如果了则直接返回</span><span style="color:#333333"><strong>if</strong></span> (stopStrategy.shouldStop(attempt)) {<span style="color:#333333"><strong>throw </strong></span> <span style="color:#333333"><strong>new</strong></span> RetryException(attemptNumber, attempt) ;} <span style="color:#333333"><strong>else</strong></span> {<span style="color:#888888">// 决定重试间隔</span><span style="color:#333333"><strong>long</strong></span> sleepTime = waitStrategy.computeSleepTime(attempt);<span style="color:#333333"><strong>尝试</strong></span>{<span style="color:#888888">// 进行阻尼</span>blockStrategy.block(sleepTime);}<span style="color:#333333"><strong>捕捉</strong></span>(InterruptedException e){Thread.currentThread().interrupt();<span style="color:#333333"><strong>抛出</strong></span> <span style="color:#333333"><strong>新</strong></span>的重试异常(尝试编号,尝试);}}}}</span></span>

非常非常地重试重试组件,使用杠铃的相关推荐

  1. 稳定性之重试,如何优雅地重试,防止系统雪崩

    背景 在微服务架构中,一个大系统被拆分成多个小服务,小服务之间大量 RPC 调用,经常可能因为网络抖动等原因导致 RPC 调用失败,这时候使用重试机制可以提高请求的最终成功率,减少故障影响,让系统运行 ...

  2. foxmail邮件加载失败重试_java retry(重试) spring retry, guava retrying 详解

    系列说明 java retry 的一步步实现机制. java-retry 源码地址 情景导入 简单的需求 产品经理:实现一个按条件,查询用户信息的服务. 小明:好的.没问题. 代码 UserServi ...

  3. 超时,重试,熔断,限流

    1 写在前面 1.1 名词解释 consumer表示服务调用方 provider标示服务提供方,dubbo里面一般就这么讲. 下面的A调用B服务,一般是泛指调用B服务里面的一个接口. 1.2 拓扑图 ...

  4. java retry(重试) spring retry, guava retrying 详解

    转载 自 http://blog.51cto.com/9250070/2156431 系列说明 java retry 的一步步实现机制. java-retry 源码地址 情景导入 简单的需求 产品经理 ...

  5. HttpInterceptor 拦截器 - 网络请求超时与重试的简单实现

    ... 拦截器在Angular项目中其实有着十分重要的地位,拦截器可以统一对 HTTP 请求进行拦截处理,我们可以在每个请求体或者响应后对应的流添加一系列动作或者处理数据,再返回给使用者调用. 每个 ...

  6. 七个必学的“RPA功能组件”技巧,把时间用在刀刃上

    Lansive RPA 可视化界面--全中文.无代码,其丰富的组件,可以实现快速的开发,以"乐高式"拼接方式轻松完成流程设计及搭建,无需任何编程经验,非IT专业人员可随需而变,业务 ...

  7. Istio组件以及架构

    Istio Istio的官网地址:Istio / 概念一些概念,理解它们有助于您更好地了解 Istio 系统的不同部分及其使用的抽象.https://istio.io/latest/zh/docs/c ...

  8. 10分钟搞定 Spring 批处理组件 —— spring-batch

    SpringBatch是什么 Spring Batch 是一个轻量级.全面的批处理框架,旨在支持开发对企业系统的日常运营至关重要的健壮批处理应用程序.Spring Batch 建立在人们所期望的 Sp ...

  9. 熔断,限流,降级 一些理解

    为什么80%的码农都做不了架构师?>>>    1 熔断,限流,降级  2 从微观角度思考   2.1 超时(timeout) 在接口调用过程中,consumer调用provider ...

  10. Resilience4j-轻量级熔断框架

    Resilience4j 简介 Resilience4j是一款轻量级,易于使用的容错库,其灵感来自于Netflix Hystrix,但是专为Java 8和函数式编程而设计.轻量级,因为库只使用了Vav ...

最新文章

  1. php display_errors
  2. Jetty在win10上的配置,IDEA中配置Jetty,Maven中配置Jetty插件,Eclipse中配置Jetty插件及其使用,通过java代码内嵌Jetty Server
  3. TCP三次握手四次挥手(图解)
  4. B. Creating the Contest(水题)
  5. 前端获取后台保存的Cookie
  6. outlook客户端接收邮件报错0x80040600
  7. Oracle如何建立多库,基于Oracle多库查询方法(分享)
  8. NYOJ 364 田忌赛马
  9. matplotlib快速画图
  10. 图像处理-HSL彩色图像均衡化
  11. md5算出来不一样_西安美发培训学校:为什么我看到的色卡上的颜色和染出来的颜色会不一样呢?...
  12. 小猫爪:PMSM之FOC控制04-SVPWM
  13. arm开发板与PC通讯及访问外网
  14. freemarker导出Word文档并在其中插入图片
  15. OpenKE 的使用(四)— HolE 和 ComplEx 论文复现
  16. crt远程连接linux目录的颜色不显示,SecureCRT连接linux设置vim显示颜色
  17. 备战蓝桥杯单片机倒数第四天 小蜜蜂老师公众号更新内容
  18. 【matlab图像处理】直方图均衡化操作
  19. C语言数据结构与算法---图的遍历
  20. SMBLoris windows拒绝服务漏洞

热门文章

  1. 世纪佳缘php查学历吗,爬了世纪佳缘后发现了一个秘密,世纪佳缘找对象靠谱吗?...
  2. 电子学会青少年软件编程 Python编程等级考试三级真题解析(选择题)2021年3月
  3. 百度世界2020技术“大阅兵”背后的营销战役
  4. 如何衡量开发人员生产力的 10 个技巧
  5. 使用ireport创建报表模板时,向subdataset中传参
  6. 软件工程基础知识 二
  7. FeedDemon获共享软件年度大奖
  8. 基于C的电子通讯录管理系统
  9. 软件工程师为什么单身的六宗罪
  10. echarts中的x轴y轴颜色,文字颜色改变