Java Retry 重试 Java 重试机制 Spring Retry 重试机制 Java Spring Retry 实现代码重试

2023-05-16

        Java Retry 重试 Java 重试机制 Spring Retry 重试机制 Java Spring Retry 实现代码重试

一、概述

        在日常开发中,可能有以下场景:

        调用第三方系统接口,因第三方接口不稳定,偶尔出现调用失败的情况,下一次调用又可能恢复正常,为了避免这种情况,我们需要用到重试机制,多次重试,尽可能避免程序结果出错 ...

        微服务feign调用时,经常出现超时情况 ,导致调用失败,实际上不是服务问题,可能是某个时刻请求太多,线程池资源不够,在排队 ... 这里也可以用上 多次重试 , 避免出错...

二、简单重试Retry

        1、一般重试机制-

        都是在 while 循环中,进行 try-catch ,若出现异常,则 间隔一定的时间,再次进行重试,直到程序执行获取到正确的结果。

        2、简单重试Retry 代码如下:



@Slf4j
public class SimpleTryTest {

    @SneakyThrows
    public static void main(String[] args) {
        int tryCount = 3 ; // 重试次数
        int num = 0 ; // 次数记录
        int n = 0 ; // 模拟异常数
        long intervalTime = 1000L ; // 间隔时间
        Exception ex = null;
        while (tryCount > num){
            try {
                if(n >= 3){
//                if(n >= 2){
                    System.out.println("n = "+n + " \t 程序执行完毕~");
                    return;
                }
                n++;
                throw new RuntimeException("异常了==>>> n ="+n);
            } catch (Exception e) {
                ex= e;
                num++;
                final String format = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
                log.error(format+" ===> 重试,第{}次",num);
            }
            TimeUnit.MILLISECONDS.sleep(intervalTime);
        }
        throw new RuntimeException("重试失败,程序执行结束 ", ex);
    }
}

        2.1、重试失败 - 执行结果如下:

21:56:47.015 [main] ERROR com.runcode.springboottourist.retry.test.SimpleTryTest - 2023-03-19 21:56:46 ===> 重试,第1次
21:56:48.038 [main] ERROR com.runcode.springboottourist.retry.test.SimpleTryTest - 2023-03-19 21:56:48 ===> 重试,第2次
21:56:49.049 [main] ERROR com.runcode.springboottourist.retry.test.SimpleTryTest - 2023-03-19 21:56:49 ===> 重试,第3次
Exception in thread "main" java.lang.RuntimeException: 重试失败,程序执行结束 
	at com.runcode.springboottourist.retry.test.SimpleTryTest.main(SimpleTryTest.java:43)
Caused by: java.lang.RuntimeException: 异常了==>>> n =3
	at com.runcode.springboottourist.retry.test.SimpleTryTest.main(SimpleTryTest.java:34)

        2.2、 重试成功 - 执行结果如下:

21:57:50.733 [main] ERROR com.runcode.springboottourist.retry.test.SimpleTryTest - 2023-03-19 21:57:50 ===> 重试,第1次
21:57:51.760 [main] ERROR com.runcode.springboottourist.retry.test.SimpleTryTest - 2023-03-19 21:57:51 ===> 重试,第2次
n = 2 	 程序执行完毕~

三、Java写个通用的重试Retry

        1、创建一个BaseRetry类,定义通用的 参数配置


@Slf4j
public class BaseRetry {

    /**
     * Description: 通用重试方法 --- 模板
     * @param param  方法入参
     * @param maxTryCount --- 最大重试次数
     * @param intervalTime --- 间隔时间
     * @return  T
     * @version v1.0
     * @author wu
     * @date 2023/3/19 21:30
     */
    public <T> T tryMethod(Object param ,int maxTryCount , long intervalTime){
        final AtomicInteger num = new AtomicInteger();
        Exception ex ;
        do{
            try {
                return exec(param);
            } catch (Exception e) {
                e.printStackTrace();
                ex = e;
            }
            num.incrementAndGet();
            log.warn("进行第:{} 次,重试中 ...",num.get());
            try {
                TimeUnit.MILLISECONDS.sleep(intervalTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }while (maxTryCount > num.get());

        throw new RuntimeException("重试失败==>",ex);
    }

    protected  <T> T exec(Object param) {
        return null;
    }
}

        2、测试 - 有实际返回值的

 static class TryOne extends BaseRetry{
        int num = 0 ;
        /**
         * Description: 有实际返回值的
         * @param param
         * @return java.lang.Integer
         * @version v1.0
         * @author wu
         * @date 2023/3/17 11:05
         */
        @Override
        protected Integer exec(Object param) {
            num++;
            if (num > 3) {
                return Integer.valueOf(num);
            }
            throw new RuntimeException("num=="+num);
        }

        public static void main(String[] args) {
            final TryOne tryOne = new TryOne();
//            final Object o = tryOne.tryMethod(null, 3, 1000L);
            final Object o = tryOne.tryMethod(null, 4, 1000L);
            System.out.println("o =="+ o);
        }
    }

        2.1、输出结果如下:

java.lang.RuntimeException: num==1
	at com.runcode.springboottourist.retry.test.RetryTest$TryOne.exec(RetryTest.java:30)
	at com.runcode.springboottourist.retry.test.RetryTest$TryOne.exec(RetryTest.java:14)
	at com.runcode.springboottourist.retry.BaseRetry.tryMethod(BaseRetry.java:32)
	at com.runcode.springboottourist.retry.test.RetryTest$TryOne.main(RetryTest.java:36)
22:01:20.763 [main] WARN com.runcode.springboottourist.retry.BaseRetry - 进行第:1 次,重试中 ...
java.lang.RuntimeException: num==2
	at com.runcode.springboottourist.retry.test.RetryTest$TryOne.exec(RetryTest.java:30)
	at com.runcode.springboottourist.retry.test.RetryTest$TryOne.exec(RetryTest.java:14)
	at com.runcode.springboottourist.retry.BaseRetry.tryMethod(BaseRetry.java:32)
	at com.runcode.springboottourist.retry.test.RetryTest$TryOne.main(RetryTest.java:36)
22:01:21.778 [main] WARN com.runcode.springboottourist.retry.BaseRetry - 进行第:2 次,重试中 ...
java.lang.RuntimeException: num==3
	at com.runcode.springboottourist.retry.test.RetryTest$TryOne.exec(RetryTest.java:30)
	at com.runcode.springboottourist.retry.test.RetryTest$TryOne.exec(RetryTest.java:14)
	at com.runcode.springboottourist.retry.BaseRetry.tryMethod(BaseRetry.java:32)
	at com.runcode.springboottourist.retry.test.RetryTest$TryOne.main(RetryTest.java:36)
22:01:22.781 [main] WARN com.runcode.springboottourist.retry.BaseRetry - 进行第:3 次,重试中 ...
o ==4

        3、测试 - 没有实际返回值的

static class TryTwo extends BaseRetry{
        int num = 0 ;

        /**
         * Description: 没有实际返回值 --- java.lang.Void
         * @param param
         * @return java.lang.Void
         * @version v1.0
         * @author wu
         * @date 2023/3/17 11:09
         */
        @Override
        protected Void exec(Object param) {
            num++;
            if (num > 3) {
               System.out.println("满足条件执行 == num="+num);
               return null;
            }
            throw new RuntimeException("num=="+num);
        }

        public static void main(String[] args) {
            final TryTwo tryTwo = new TryTwo();
//            final Object o = tryTwo.tryMethod(null, 3, 1000L);
            final Object o = tryTwo.tryMethod(null, 4, 1000L);
            System.out.println("o =="+ o);
        }
    }

        3.1、输出结果如下:

java.lang.RuntimeException: num==1
	at com.runcode.springboottourist.retry.test.RetryTest$TryTwo.exec(RetryTest.java:59)
	at com.runcode.springboottourist.retry.test.RetryTest$TryTwo.exec(RetryTest.java:41)
	at com.runcode.springboottourist.retry.BaseRetry.tryMethod(BaseRetry.java:32)
	at com.runcode.springboottourist.retry.test.RetryTest$TryTwo.main(RetryTest.java:65)
22:02:13.988 [main] WARN com.runcode.springboottourist.retry.BaseRetry - 进行第:1 次,重试中 ...
java.lang.RuntimeException: num==2
	at com.runcode.springboottourist.retry.test.RetryTest$TryTwo.exec(RetryTest.java:59)
	at com.runcode.springboottourist.retry.test.RetryTest$TryTwo.exec(RetryTest.java:41)
	at com.runcode.springboottourist.retry.BaseRetry.tryMethod(BaseRetry.java:32)
	at com.runcode.springboottourist.retry.test.RetryTest$TryTwo.main(RetryTest.java:65)
22:02:14.993 [main] WARN com.runcode.springboottourist.retry.BaseRetry - 进行第:2 次,重试中 ...
java.lang.RuntimeException: num==3
	at com.runcode.springboottourist.retry.test.RetryTest$TryTwo.exec(RetryTest.java:59)
	at com.runcode.springboottourist.retry.test.RetryTest$TryTwo.exec(RetryTest.java:41)
	at com.runcode.springboottourist.retry.BaseRetry.tryMethod(BaseRetry.java:32)
	at com.runcode.springboottourist.retry.test.RetryTest$TryTwo.main(RetryTest.java:65)
22:02:15.999 [main] WARN com.runcode.springboottourist.retry.BaseRetry - 进行第:3 次,重试中 ...
满足条件执行 == num=4
o ==null

四、Spring Retry Spring重试机制

        1、​  Spring Retry 组件

        看了上面2个案例,每次都需要继承类,重写方法,还要进行一堆配置,太麻烦,有没有更简单的办法的呢. 答案是:有的! Spring 已经准备好了, Spring Retry 组件,程序执行遇到异常时的重试,下面开始使用。

        2、引入依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.retry</groupId>
   <artifactId>spring-retry</artifactId>
   <version>1.3.4</version>
</dependency>

        3、Application启动类,使用注解 @EnableRetry 开启

@EnableRetry
@SpringBootApplication
public class SpringBootTouristApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringBootTouristApplication.class, args);
   }

}

        4、@Retryable 注解:重试相关的策略

private int num = 0 ;

@Retryable(value = Exception.class,maxAttempts = 3 ,backoff = @Backoff(delay = 2000,multiplier = 1.5))
public Integer get(int n) {
    num++;
    if (num >= 3) {
        return Integer.valueOf(num);
    }
    final String date = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
    throw new RuntimeException(date +" ===> num=="+num);
}

public Integer getVal() {
    return num;
}
public void set(int n){
    this.num = n;
}

        5、@Recover 注解: 定义重试失败后的回调

/**
 * Description: 重试失败的回调方法
 * @param e 失败的异常
 * @param n --- 方法的入参
 * @return  java.lang.Integer
 * @version v1.0
 * @author wu
 * @date 2023/3/19 21:17
 */
@Recover
public Integer recover(Exception e,int n){
    log.error("retry 重试失败,入参是 n={}",n);
    log.error("retry failure , cause by {}", ExceptionUtils.getStackTrace(e));
    return 1234;
}

        6、创建 RetryController 进行相关测试


@RequestMapping("/retry")
@RestController
public class RetryController {

    @Autowired
    private RetryService retryService;

    @RequestMapping("/get")
    public String get(){
        final Integer s = retryService.get(5200);
        return "获取到的返回值是: s="+s;
    }

    @RequestMapping(value = "/set")
    public String set(Integer n){
        if(Objects.isNull(n)){
            n=0;
        }
        retryService.set(n);
        final Integer val = retryService.getVal();
        return "set成功, num val ="+val ;
    }

}

        7.1、重试成功 --- 不触发 recover 方法

1、 调用:http://localhost:8080/retry/set?n=-0 

2、 调用: http://localhost:8080/retry/get

--- 返回值是:
获取到的返回值是: s=3

        7.2、重试失败 --- 触发 recover 方法

1、 调用:http://localhost:8080/retry/set?n=-2 

2、 调用: http://localhost:8080/retry/get

--- 返回值是:
获取到的返回值是: s=1234

--- 控制台异常输出: 
2023-03-19 22:28:38.107 ERROR 67104 --- [nio-8080-exec-7] c.r.s.service.RetryService               : retry 重试失败,入参是 n=5200
2023-03-19 22:28:38.110 ERROR 67104 --- [nio-8080-exec-7] c.r.s.service.RetryService               : retry failure , cause by java.lang.RuntimeException: 2023-03-19 22:28:38 ===> num==1
	at com.runcode.springboottourist.service.RetryService.get(RetryService.java:32)
 ... ingore
 

五、总结

        1、spring-retry,最新的版本是:2.0.0 ,该版本要求JDK版本是:17 , 还是Java8,请使用1.3.x 版本的。

         

        启动异常,如下:

 

        2、@Retryable 各个参数的作用,请参考 官方文档,或者亲自试一试,去 org.springframework.retry.annotation.Retryable 里面查看。

         

        3、Spring Retry 实现原理,参考:Spring Retry 的使用和原理_sgvshy的博客-CSDN博客

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java Retry 重试 Java 重试机制 Spring Retry 重试机制 Java Spring Retry 实现代码重试 的相关文章

  • 强化学习Q-learning入门教学

    1 问题描述 2 图形化展示 3 reward矩阵构建 4 Q表构建 这里需要说明的是Q表的转移规则原本是 xff1a 本例中为了方便介绍 xff0c 将 值设为1了 原文讲解的通俗易懂 xff0c 有兴趣的可以看一下 出处 xff1a h
  • 英文文献代码查找

    原文链接 xff1a https blog csdn net weixin 45656790 article details 109271019
  • Word中插入集合和元素的包含符号

    1 比较简单 xff0c 是元素和集合的包含关系 查找 xff1a word gt 插入 gt 符号栏下拉 xff0c 选择基础数学 2 集合间的包含关系 四个数字 xff0c 代表一个 输入文档中的指定位置 xff0c 选中数字以后 xf
  • 微信PC端聊天界面表情包无法显示

    我试成功的一个办法 xff0c 分享一下 具体步骤 xff1a 1 找到微信聊天界面的设置选项 xff0c 如图 2 进入微信文件保存位置 3 进入WeChat Files All Users config目录 4 删除config dat
  • MathType 提示需要一个新版本的MT Extra(True Type)字体

    1 打开C Windows Fonts文件夹 xff0c 若里面有MT Extra TrueType 字体或其快捷方式 xff0c 则将其删除 2 找到MathType安装目录下C Program Files x86 MathType Fo
  • Word快捷键设置上下标;Word取消表格虚线;Word查找数学符号

    问题1 快捷键设置上下角标 这个在论文写作时比较常用 xff0c 本人也是最近在写大论文 xff0c 遇到了这个情况 Word和Visio中 xff0c 都可以使用 步骤 xff1a 选中即将成为上下标的内容 xff0c 上标快捷键 xff
  • xcode中xib使用之轻松学习

    1 创建xib文件 在工程目录中New Files xff0c 选择user interface类型中的empty创建一个空的interface builder document文件 文件名没有强制的要求 xff0c 最好使用 前缀 xff
  • 用Opencv打造一台自动视觉目标跟踪系统

    平移 倾斜伺服装置 xff0c 帮助摄像机使用视觉自动跟踪颜色对象 简介 现在我们将使用我们的设备帮助相机自动跟踪颜色对象 xff0c 如下所示 xff1a OpenCV可免费用于学术和商业用途 它具有C 43 43 xff0c C xff
  • error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools"【转载+修改】

    error Microsoft Visual C 43 43 14 0 is required Get it with Microsoft Visual C 43 43 Build Tools http landinghub visuals
  • 如何使用OpenCV实现多张图像拼接

    先来看看OpenCV官方的例子得到效果是非常的好 xff0c 输入的images如下 xff1a 效果 xff1a Stitcher类与detail命名空间 OpenCV提供了高级别的函数封装在Stitcher类中 xff0c 使用很方便
  • 如何使用OpenCV对物体进行搜索检测与识别

    在本教程中 xff0c 我们将了解对象检测中称为 选择性搜索 的重要概念 我们还将用C 43 43 和Python共享OpenCV代码 物体检测与物体识别 对象识别算法识别图像中存在哪些对象 它将整个图像作为输入 xff0c 并输出该图像中
  • 一种基于深度学习的方法来检测摩托车头盔的使用

    背景 据统计使用摩托车头盔可以将道路交通事故中摩托车驾驶员致命伤害的可能性降低42 xff05 xff0c 尽管如此 xff0c 遵守摩托车头盔还是较少 xff0c 尤其是在发展中国家 xff0c 为了有效开展针对性的头盔使用运动 xff0
  • 偏振光相机1——偏振光

    光的电磁波属性 光是一种电磁波 xff0c 这个概念大家应该不陌生 既然是电磁波 xff0c 那我们从电磁波的特性上来看它有哪些属性 用图1中的交变电磁场来描述光的特性 xff0c 电场和磁场在空间中相互垂直 xff0c 它们同时与光的传播
  • 偏振光相机2——索尼大法

    Stokes参量 在上一篇 偏振光相机 偏振光 中 xff0c 我们知道偏振光有线性偏振光 椭圆偏振光 圆偏光 那么如何定量的描述偏振光呢 xff1f Stokes矢量是一种广泛用来描述偏振光属性的方法 图1 不同类型的偏振光 线性偏振光和
  • 偏振光相机3——偏振应用

    在之前的2篇中 xff0c 介绍了偏振光的基本概念和基于SONY最新CMOS偏振传感器芯片的相机 在本篇中 xff0c 我们来看看偏振相机的一些应用 偏振相机的应用离不开偏振光 xff0c 那么先看看如何得到偏振光信息 如何获取偏光 在 偏
  • 【干货】生成对抗网络GANs算法在医学图像领域应用总结

    Goodfellow等人 介绍了生成对抗网络 xff08 GAN xff09 以模拟数据分布 由于与两个基本属性相关的原因 xff0c GAN可以合成真实图像 GAN是一种无监督的训练方法 xff0c 可以通过类似于人类学习图像特征的方式获
  • 图像算法之3D人脸识别技术原理概述

    随着深度学习技术的进步 xff0c 面部相关任务的研究也成为学术界和工业界的热门话题 众所周知的面部任务通常包括面部检测 xff0c 面部识别 xff0c 面部表情识别等 xff0c 其主要使用2D RGB面部 xff08 通常包括一些纹理
  • 如何使用OpenCV计算机视觉检测帕金森病图片

    在本教程中 xff0c 您将学习如何使用OpenCV和机器学习在手绘的螺旋和波浪图像中自动检测帕金森病 本教程来自来自巴西的博士生Joao Joao有兴趣利用计算机视觉和机器学习基于几何图形 xff08 即螺旋和符号波 xff09 自动检测
  • OpenCV快速寻找图像差异

    如何使用结构相似性指数 xff08 SSIM xff09 将两个图像与Python进行比较 使用这种方法 xff0c 我们能够轻松确定两个图像是否相同或由于轻微的图像处理 xff0c 压缩伪像或有目的的篡改而产生差异 今天我们将扩展SSIM
  • C++17使用std::optional表示一个可能存在的值

    文章目录 前言返回一个bool值使用 std optional 改写总结 前言 平时写代码会遇到一种传递参数特殊值标记特殊流程 xff0c 或者函数返回值存在魔法数的情况 xff0c 很需要一种标记参数或返回值状态的结构 xff0c 那么在

随机推荐