用两行代码实现重试功能,spring-retry真是简单而优雅

最近做的一个需求,需要调用第三方接口。正常情况下,接口的响应是符合要求的,只有在网络抖动等极少数的情况下,会存在超时情况。因为是小概率事件,所以一次超时之后,进行一次重试操作应该就可以了。重试很简单,设定最多的重试次数,用一个循环来实现就好了。比如一次请求是这样:

@Controller
public class RetryController {
    @Autowired
    private RetryRequestService retryRequestService;

    public String doSth(String param) {
        String result = retryRequestService.request(param);
        return "响应是" + result;
    }
}

改成重试三次,可以是这样:

@Controller
public class RetryController {
    @Autowired
    private RetryRequestService retryRequestService;

    public String doSth(String param) {
        int count = 0;
        String result = "";
        while (count < 3) {
            try {
                result = retryRequestService.request(param);
                break;
            } catch (Exception e) {
                count++;
            }
        }
        return "响应是" + result;
    }
}

如果请求接口超时(抛异常)了,那么会继续进入下一次循环重试。如果在超时时间内获取到了结果,那就结束循环,继续往下走。

用倒是能用,但是太丑了。不好看,还狠狠的侵入了原有的代码。所以有没有更优雅的方式呢?

快速接入spring-retry

这么常用的东西,肯定有轮子啊!于是spring-retry闪亮登场!

这是一个属于Spring全家桶的项目,也是被广泛运用的组件。在这里我默认你是个Spring Boot的项目了哈。

使用起来非常简单,只需要三步。


  org.springframework.retry
  spring-retry

  org.springframework
  spring-aspects

此举是让你的Spring Boot项目支持spring-retry的重试功能。像这样:

@SpringBootApplication
@EnableRetry
@Slf4j
public class FastKindleApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(FastKindleApplication.class, args);
        String result = applicationContext.getBean(RetryController.class).doSth("");
        log.info(result);
    }
}

如上文所说,我们需要重试的方法是retryRequestService.request这个方法。那么我们就在这个方法上加@Retryable注解。如下:

@Service
@Slf4j
public class RetryRequestService {
    @Autowired
    private OtherSystemSpi otherSystemSpi;

    @Retryable(value = RuntimeException.class, maxAttempts = 5, backoff = @Backoff(delay = 100))
    public String request(String param) {
        double random = Math.random();
        log.info("请求进来了,随机值为:" + random);
        if (random > 0.1) {
            throw new RuntimeException("超时");
        }
        return otherSystemSpi.request(param);
    }
}

当然,我们这里写了个调皮的逻辑来模拟超时。如果随机值大于0.1则抛出一个RuntimeException异常。每次请求进来时都会输出日志。

我来解释一下@Retryable注解中的信息。

  • value = RuntimeException.class:是指方法抛出RuntimeException异常时,进行重试。这里可以指定你想要拦截的异常。
  • maxAttempts:是最大重试次数。如果不写,则是默认3次。
  • backoff = @Backoff(delay = 100):是指重试间隔。delay=100意味着下一次的重试,要等100毫秒之后才能执行。

我们来执行一下,可以看到日志输出:

2022-03-15 23:51:19.754  INFO 3343 --- [main] c.e.fastkindle.FastKindleApplication     : Started FastKindleApplication in 0.347 seconds (JVM running for 0.536)
2022-03-15 23:51:19.762  INFO 3343 --- [main] c.e.f.service.retry.RetryRequestService  : 请求进来了,随机值为:0.11030214774098712
2022-03-15 23:51:19.867  INFO 3343 --- [main] c.e.f.service.retry.RetryRequestService  : 请求进来了,随机值为:0.09624689154608002
2022-03-15 23:51:19.867  INFO 3343 --- [main] c.e.fastkindle.FastKindleApplication     : 响应是mock

前两次的随机值都大于0.1,所以进行了重试,而且注意时间,都是间隔了大概100毫秒输出的日志。第三次的随机值小于0.1,就直接返回数据了。

我又试了几次,使五次请求的随机值都大于0.1,则结果是进行了五次请求,最后抛出了个异常。

2022-03-15 23:52:58.193  INFO 3449 --- [main] c.e.fastkindle.FastKindleApplication     : Started FastKindleApplication in 0.41 seconds (JVM running for 0.635)
2022-03-15 23:52:58.201  INFO 3449 --- [main] c.e.f.service.retry.RetryRequestService  : 请求进来了,随机值为:0.5265644192525288
2022-03-15 23:52:58.303  INFO 3449 --- [main] c.e.f.service.retry.RetryRequestService  : 请求进来了,随机值为:0.6343538744876432
2022-03-15 23:52:58.407  INFO 3449 --- [main] c.e.f.service.retry.RetryRequestService  : 请求进来了,随机值为:0.5482463853575078
2022-03-15 23:52:58.511  INFO 3449 --- [main] c.e.f.service.retry.RetryRequestService  : 请求进来了,随机值为:0.5624923285641071
2022-03-15 23:52:58.616  INFO 3449 --- [main] c.e.f.service.retry.RetryRequestService  : 请求进来了,随机值为:0.305945622979098
Exception in thread "main" java.lang.RuntimeException: 超时
        at com.esparks.fastkindle.service.retry.RetryRequestService.request(RetryRequestService.java:24)
        at com.esparks.fastkindle.service.retry.RetryRequestService$$FastClassBySpringCGLIB$$50f0bdca.invoke()
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)

好啦,咱今天就介绍一下快速的接入spring-retry来实现重试功能。更详细的功能和实现原理,之后再详细介绍吧(又给自己挖了个坑)

Original: https://www.cnblogs.com/codeflyer/p/16023257.html
Author: 小白码上飞
Title: 用两行代码实现重试功能,spring-retry真是简单而优雅

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/570692/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 2019 年软件开发人员必学的编程语言 Top 3

    AI 前线导读:这篇文章将探讨编程语言世界的现在和未来,这些语言让新一代软件开发者成为这个数字世界的关键参与者,他们让这个世界变得更健壮、连接更加紧密和更有意义。开发者要想在 20…

    Java 2023年6月15日
    071
  • ucore操作系统学习(六) ucore lab6线程调度器

    ucore在lab5中实现了较为完整的进程/线程机制,能够创建和管理位于内核态或用户态的多个线程,让不同的线程通过上下文切换并发的执行,最大化利用CPU硬件资源。ucore在lab…

    Java 2023年6月8日
    067
  • NO6 软件开发项目维护的开发可行性方案 (设计三步之二)

    软件开发项目维护的开发可行性方案(本文为ppt,可以在文件中看到对应ppt文件) xxxx:李海波 (v1.0) 大哉乾元 2016/7/17 作者原创转载请注明出处 目录 — 方…

    Java 2023年6月8日
    070
  • Aop-Transaction事物

    事物注解:@Transactional 事物举例: sql: undefined DROP TABLE IF EXISTS account;CREATE TABLE account…

    Java 2023年6月5日
    059
  • 如何下载 blob 地址的视频资源

    如何下载视频资源以blob:http开头的资源 一、问题场景 想下载知乎视频资源,却发现视频链接是这个样子的 blob:https://v.vzuu.com/b6146956-6e…

    Java 2023年6月9日
    0100
  • Redis 5 种基本数据结构(String、List、Hash、Set、Sorted Set)详解 | JavaGuide

    首发于:Redis 5 种基本数据结构详解 – JavaGuide相关文章:Redis常见面试题总结(上) 。 Redis 5 种基本数据结构(String、List、…

    Java 2023年6月9日
    053
  • 教你win7系统手动导入注册表获取管理员权限

    想必大家都遇到过win7系统手动导入注册表获取管理员权限的问题吧,大多数朋友还不知道怎么处理固然处理起来也不难,然而还是有一些小伙伴不明白win7系统手动导入注册表获取管理员权限应…

    Java 2023年5月30日
    077
  • Unity-2D

    Unity-2D 1.Unity中的2D模式: 1)游戏在二维上展示 启用 2D 模式时将会设置正交(即无透视)视图:摄像机沿 Z 轴观察,而 Y 轴向上增加。因此可以轻松可视化场…

    Java 2023年6月13日
    065
  • 高速缓存一致性协议MESI与内存屏障

    CPU高速缓存机制的引入,主要是为了解决CPU越来越快的运行速度与相对较慢的主存访问速度的矛盾。CPU中的寄存器数量有限,在执行内存寻址指令时,经常需要从内存中读取指令所需的数据或…

    Java 2023年6月8日
    058
  • Spring Boot2 核心功能

    1、文件类型 1、1 properties yml 控制台输出 单引号会将\n作为字符串输出 双引号会换行输出 单引号会转义,双引号不会转义 person: userName: &…

    Java 2023年6月13日
    076
  • 【校招VIP】[前端][二本][5分]简历的板式比较标准

    关注【校招VIP】 公众号,回复【简历】 ,添加校招顾问微信,即可获取简历指导! 本份简历是一位21届二本前端同学的简历,简历评分6分。 一、学员简历 二、指导意见 简历的版式没有…

    Java 2023年6月5日
    092
  • Mysql 安全加固经验总结

    本文为博主原创,转载请注明出处: 1.内网部署Mysql mysql 数据库在使用过程中,需要给服务提供连接和访问的权限,而不需要进行公网连接和访问,所以在安全环境和现网环境部署m…

    Java 2023年6月8日
    067
  • 为了更好的吃这个瓜,我去拉了一下评论,吵起来了,太有意思了。

    你好呀,我是歪歪。 周末的时候吃了一个瓜,真的是太好吃了。 虽然 2022 年都还没过半,但是我个人已经把这个瓜评选为年度前三了。很久没有吃过这么有质量,又让我酣畅淋漓的瓜了。 事…

    Java 2023年6月5日
    082
  • 微服务开发框架 SpringCloud

    今天给大家介绍一下微服务开发框架 SpringCloud。 概述 微服务架构是当前软件开发领域的技术热点。它在各种博客、社交媒体和会议演讲上的出镜率非常之高。大家以前可能或多或少听…

    Java 2023年5月30日
    087
  • SpringMVC的文件上传下载,异常处理,拦截器的小总结

    文件的上传和下载 我们通常在访问网页时会使用到文件的上传与下载的功能,那么他是如何实现的呢? ResponseEntity :用于控制器方法的返回值类型,该控制器方法的返回值就是响…

    Java 2023年6月8日
    060
  • 2018-2021我的开源项目总结

    本人18年6月份毕业在武汉找了第一份 java开发工作4500(面试时被hr压了500,武汉当时行情第一年5000), 做的oa、库存管理相关系统,公司内系统架构主要是ssh,页面…

    Java 2023年6月13日
    078
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球