当前位置: 首页 > news >正文

Springboot 使用 Guava 的重试Retry ,轻便灵活

前言

重试,我承认是冷饭重炒了。 之前写过一些关于重试相关的实践介绍文章:

Spring的Retry《Springboot 整合Retry 实现重试机制》:

https://blog.csdn.net/qq_35387940/article/details/99676114

使用DelayQueue 实现了更加动态灵活的 延迟重试:

《Springboot 指定重发的次数和延迟时间,定时异步执行 重发任务》:https://blog.csdn.net/qq_35387940/article/details/105578433

今天,再给大家带来一个又轻又灵活的重试框架整合 ,就是Guava 的重试Retry 。
 


正文

先给大家看看这个Guava的Retry的几个核心玩法 :

1. 出现异常时重试 ;

出现指定异常时重试;

出现指定异常,里面的提示语或者code等于指定值时重试等。

2.方法返回值等于指定值时重试 ,(String、Integer、Boolean等等都可以,甚至对象等)

3.等待多少秒重试;

固定等待多少秒重试;

随机范围内等待多少秒重试;

不等待秒数直接重试;

增长式等待秒数重试等

4.到达重试多少次数后停止;

不停止,一直重试;

一定时间内,一直重试,然后再停止;

5.重试监听器,每次重试调用监听器里面的方法(可以多个,按照顺序调用)



下面我们来实战一下,写点代码熟悉一下:

1.pom.xml文件引入相关jar:

<dependency>
    <groupId>com.github.rholder</groupId>
    <artifactId>guava-retrying</artifactId>
    <version>2.0.0</version>
</dependency>

2.新建一个 RetryUtil.java :
 

写一个业务方法,举例 :
 

public Boolean shopping(){}

这个方法我们业务要求,如果购买下单不成功就进行重试 :

核心方法,通过RetryerBuilder建造一个重试器:

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()

这个重试器,可以设置各种各样的触发条件、要求,也就是我们文章开头提到的各种玩法。

贴一个写好的代码例子:

import com.github.rholder.retry.*;
import com.google.common.base.Predicates;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * @Author JCccc
 * @Description
 * @Date 2021/10/12 9:26
 */
public class RetryUtil {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    public Boolean shopping() throws Exception {
        //定义重试机制
        Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                //retryIf 重试条件
                .retryIfException()
                .retryIfRuntimeException()
                .retryIfExceptionOfType(Exception.class)
                .retryIfException(Predicates.equalTo(new Exception()))
                .retryIfResult(Predicates.equalTo(false))

                //等待策略:每次请求间隔1s
                //fixedWait 固定X秒后重试
                //noWait不等时间直接重试
                //incrementingWait 第一个参数为第一次重试时间,后面会通过设置间隔递增秒数重试
                //randomWait 随机等待设置范围内的时间重试
                .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))

                //停止策略 : 尝试请求6次
                .withStopStrategy(StopStrategies.stopAfterAttempt(6))

               
                .withRetryListener(new MyRetryListener())
                .withRetryListener(new MyRetryListener2())
                .build();


        //定义请求实现
        Callable<Boolean> callable = new Callable<Boolean>() {
            int times = 1;

            @Override
            public Boolean call() throws Exception {
                log.info("重试调用={}", times);
                times++;
                return placeOrder();
            }
        };
        //利用重试器调用请求
        return retryer.call(callable);
    }


    /**
     * 下单业务方法 模拟
     *
     * @return
     */
    public Boolean placeOrder() {
        int number = new Random().nextInt(11);
        System.out.println("number:"+number);
        if (7 < number) {
            //模拟下单成功
            log.info("下单成功");
            return true;
        }
        log.info("下单失败");
        return false;
    }


    private static class MyRetryListener implements RetryListener {
        @Override
        public <V> void onRetry(Attempt<V> attempt) {
            System.out.println("回调监听器 一,当前是第:"+attempt.getAttemptNumber()+ "次执行");
            
        }
    }

    private static class MyRetryListener2 implements RetryListener {
        @Override
        public <V> void onRetry(Attempt<V> attempt) {
            System.out.println("回调监听器 二:记录日志"+attempt.getAttemptNumber());
        }
    }

    public static void main(String[] args) throws Exception {
        RetryUtil retryUtil = new RetryUtil();
        Boolean result = retryUtil.shopping();
        System.out.println(result);
    }

}

 

 其实代码里,注释也已经很明白。我在代码里面模拟了一个简单的下单逻辑,如果下单方法返回的数字大于7,代表下单成功,其他情况都需要重试。

代码简述:

 

 

运行一下,看看结果:


可以看到每次重试都会按顺序调用我配置的两个监听器里面的方法;

前面两次下单返回数字都小于7,所以继续触发重试,第三次下单成功结束重试。

 

接着我们继续探索一下,这里的重试监听器,可以看到我们的接受参数是

Attempt

这玩意,其实里面也记录整个重试过程中各种元素。

获取触发重试的异常的原因:
public Throwable getExceptionCause() throws IllegalStateException; 

配合 attempt.hasException()使用 ,如果异常存在,那么就拿出异常原因,这样在监听器里面我们就能扩展一些业务逻辑了。

获取当前重试的次数:

public long getAttemptNumber() ;

同样,如果我们业务逻辑需要,在重试次数打到某一个数进行业务扩展时,这个方法就可以用上了,当然用来记录方法重试次数时也是用得上的。
 

获取距离第一次重试的延迟:

public long getDelaySinceFirstAttempt();

获取重试返回的结果:

public V getResult() throws IllegalStateException;

那么同样,还有关于重试器里的方法,大家感兴趣也是可以点进源码里面,自己探索一下:

以上这几个策略配置器,支持的方法远不止我代码里面介绍的,其实还有很多,例如间隔设置,使用斐波那契增量计算时间等等。 

相关文章:

  • Springboot Async异步扩展使用 结合 CompletableFuture
  • Springboot Condition 实用讲解,只看一遍包学会
  • 聊点不一样的,初级软件测试岗需要做些什么?
  • 聊一聊多线程的 run() 和 start(),挖一挖start0
  • JAVA 继承Thread 实现多线程 资源不共享? 请保持清醒 。
  • SpringBoot 事件发布监听机制使用、分析、注意点 (一篇到位)
  • Springboot yml配置参数数据加密 (数据加密篇 一)
  • Springboot AOP实现指定敏感字段数据加密 (数据加密篇 二)
  • Springboot 使用mysql加密解密函数 (数据加密篇 三)
  • Java List数据量大, 需要分片批次操作
  • Springboot yml配置参数加密 ,jasypt自定义解密器(拓展篇)
  • Springboot 自定义mybatis 拦截器,实现我们要的扩展
  • Eureka 一直刷 Running the evict task with compensationTime 0ms
  • Eureka 注册、下线、续约事件的监听使用
  • Java Thread.sleep(),结合例子只学一次
  • egg(89)--egg之redis的发布和订阅
  • MQ框架的比较
  • PAT A1092
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • SQLServer插入数据
  • 回顾 Swift 多平台移植进度 #2
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 数据仓库的几种建模方法
  • 原创:新手布局福音!微信小程序使用flex的一些基础样式属性(一)
  • NLPIR智能语义技术让大数据挖掘更简单
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​【已解决】npm install​卡主不动的情况
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (+4)2.2UML建模图
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (转)3D模板阴影原理
  • (转)大型网站的系统架构
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .apk文件,IIS不支持下载解决
  • .equals()到底是什么意思?
  • .Net 4.0并行库实用性演练
  • .NET Framework杂记
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • .netcore 如何获取系统中所有session_如何把百度推广中获取的线索(基木鱼,电话,百度商桥等)同步到企业微信或者企业CRM等企业营销系统中...
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .net生成的类,跨工程调用显示注释
  • .net实现客户区延伸至至非客户区
  • .net网站发布-允许更新此预编译站点
  • .NET运行机制
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • @EnableAsync和@Async开始异步任务支持
  • @manytomany 保存后数据被删除_[Windows] 数据恢复软件RStudio v8.14.179675 便携特别版...
  • @media screen 针对不同移动设备