SpringBoot:SpringBoot中调用失败如何重试

news2024/12/29 13:44:43

一、引言

  在实际的应用中,我们经常需要调用第三方API来获取数据或执行某些操作。然而,由于网络不稳定、第三方服务异常等原因,API调用可能会失败。为了提高系统的稳定性和可靠性,我们通常会考虑实现重试机制。

  Spring Retry为Spring应用程序提供了方法级别的重试机制,帮助开发者处理由于网络不稳定、服务不可用、数据库临时性问题、外部依赖故障等原因导致的瞬时性故障。通过配置重试策略,可以确保应用程序在特定情况下能够自动进行重试,从而提高系统的健壮性和可用性。

  本文将深入探讨如何在Spring Boot项目中优雅地使用Spring Retry重试调用第三方API,并结合代码示例,展示具体实现方式。

二、重试机制的必要性

  提高系统的可用性:在网络通信、数据库操作、远程服务调用等场景中,由于网络抖动、服务暂时不可用或超时等原因,单次操作可能会失败。引入重试机制可以在这些情况下自动重新尝试操作,从而提高系统的可用性和容错能力。

  优化用户体验:对于用户来说,遇到操作失败时,他们期望系统能够自动处理并恢复,而不是需要他们手动重新尝试。重试机制可以在用户无感知的情况下自动进行,从而提供更好的用户体验。

  减少人工干预:在没有重试机制的情况下,一旦操作失败,可能需要人工进行干预和修复。这不仅增加了运维成本,而且可能导致响应延迟。重试机制可以自动处理大多数可恢复的失败情况,减少人工干预的需要。

  降低故障率:有些故障是暂时的,例如网络短暂中断或数据库连接超时。在这种情况下,立即重试操作很可能会成功。重试机制可以在这些情况下自动重试,从而降低故障率。

三、使用场景

  远程调用和网络通信:由于网络不稳定或服务不可用,可能会出现连接问题,Spring Retry可以帮助处理这类问题。

  数据库交互:执行SQL查询或更新操作时,数据库服务器可能会出现临时性的问题,如死锁或连接丢失,Spring Retry可以提供重试机制。

  外部依赖:如果应用程序依赖于外部服务、硬件设备或其他不可控因素,而这些依赖可能会偶尔出现故障或不可用状态,Spring Retry可以确保应用程序能够自动进行重试。

  并发控制:在多线程环境中,可能会出现竞争条件或并发问题,导致某些操作失败,Spring Retry可以帮助处理这类并发问题。

  复杂的业务逻辑:某些业务逻辑可能需要多次尝试才能成功,Spring Retry提供了重试机制来支持这类业务逻辑。

四、Spring Retry在项目中应用

1. 添加依赖

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

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

2. 在需要重试的方法上添加@Retryable注解,并指定可重试的异常类型、最大重试次数等参数

@Retryable(value = {SomeException.class}, maxAttempts = 2, backoff = @Backoff(delay = 2000))
@Override
 public void testRetry() {
     // 业务场景
     System.out.println("执行业务了...");
     // 模拟执行可能会失败的操作 ...
     throw new SomeException("run failed"); // 示例:抛出异常以触发重试

 }

 // 定义自定义异常类(如果需要)
 public static class SomeException extends RuntimeException {
     public SomeException(String message) {
         super(message);
     }
 }
@RestController
public class RetryController {

    @Autowired
    private RetryService retryService;

    @RequestMapping("/retry/test")
    public Object retryTest() {

        retryService.testRetry();

        return "success";
    }
}

3. 运行结果

在这里插入图片描述
4. 注解说明

@Retryable 注解

  value:可重试的异常类型。含义同include。默认为空(如果excludes也为空,则重试所有异常)

  include:可重试的异常类型。默认为空(如果excludes也为空,则重试所有异常)

  exclude:无需重试的异常类型。默认为空(如果includes也为空,则重试所有异常)

  maxAttempts:最大重试次数(包括第一次失败),默认为3次

  backoff:重试等待策略,下面会在@Backoff中介绍

  recover:表示重试次数到达最大重试次数后的回调方法

@Backoff 注解

value
  默认为1000L,重试之间的基础延迟时间(以毫秒为单位)。当没有设置 delay时,value将作为首次重试的延迟时间。之后,如果multiplier不为0,则后续的延迟时间会根据 value和multiplier来计算

delay
  默认为0,首次重试之前的延迟时间(以毫秒为单位)。如果设置为0,则不等待直接进行首次重试。如果同时设置了value和delay,则delay优先。

maxDelay
  默认为0,重试之间延迟时间的上限(以毫秒为单位)。如果计算出的延迟时间超过了这个值,则实际的延迟时间将被限制为maxDelay。这个参数用于防止延迟时间无限增长,从而避免过长的等待时间。

multipler
  默认为0.0。用于计算递增等待时间的乘数。例如,如果设置为1.5,则每次重试的等待时间将是前一次的1.5倍。
  示例:backoff = @Backoff(delay = 200, multiplier = 1.5),在这个例子中,首次重试会等待200毫秒,第二次会等待300毫秒(200毫秒1.5),第三次会等待450毫秒(300毫秒1.5),以此类推。

delayExpression
  评估标准退避期的表达式。在指数情况下用作初始值*,在均匀情况下用作最小值。覆盖 delay。

maxDelayExpression
  该表达式计算重试之间的最大等待时间(以毫秒为单位)。 如果小于delay,那么将应用30000L为默认值。覆盖maxDelay。

multiplierExpression
  评估为用作乘数的值,以生成退避的下一个延迟。覆盖multiplier。 返回一个乘数表达式,用于计算下一个退避延迟

random
  默认为false,在指数情况下multiplier > 0将此值设置为true可以使后退延迟随机化,从而使最大延迟乘以前一延迟,并且两个值之间的分布是均匀的。

五、重试还是失败,如何解决?

除了重试,我们可能还希望在多次重试失败后执行降级操作,以避免一直等待不确定的恢复时间。

@Recover注解

可以使用@Recover注解来指定一个方法来处理所有由@Retryable注解标注的方法抛出的异常。当重试次数耗尽后,会调用这个方法

 @Recover
 public void recover(SomeException e) {
      // 处理重试失败后的逻辑
      System.out.println("recover from " + e.getMessage());
  }

注意

由于Spring Retry用到了aspect增强,所有会有aspect的坑,就是方法内部调用,会使aspect增强失效,那么retry当然也会失效

public void A(){
	B();
}


//这里B不会执行
@Retryable(value = {SomeException.class}, maxAttempts = 2, backoff = @Backoff(delay = 2000))
public void B(){
	throw new SomeException("run failed");
}

  @Recover 注解来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中),此注解注释的方法参数一定要是 @Retryable 抛出的异常,否则无法识别。

六、重试当中的策略

1. @Backoff 的参数会影响我们使用哪种退避策略

  FixedBackOffPolicy:默认退避策略,每1秒重试1次

  ExponentialBackOffPolicy:指数退避策略,当设置multiplier时使用,每次重试时间间隔为 当前延迟时间 * multiplier。

  例如:默认初始1秒,系数是2,那么下次延迟2秒,再下次就是延迟4秒,如此类推,最大30秒。

  ExponentialRandomBackOffPolicy:指数随机退避策略。在指数退避策略的基础上增加了随机性。

  UniformRandomBackOffPolicy:均匀随机策略,设置maxDely但没有设置multiplier时使用,重试间隔会在maxDelay和delay间随机

2. 重试策略

  SimpleRetryPolicy:默认最多重试 3 次

  TimeoutRetryPolicy:默认在 1 秒内失败都会重试

  ExpressionRetryPolicy:符合表达式就会重试

  CircuitBreakerRetryPolicy:增加了熔断的机制,如果不在熔断状态,则允许重试

  CompositeRetryPolicy:可以组合多个重试策略

  NeverRetryPolicy:从不重试(也是一种重试策略哈)

  AlwaysRetryPolicy:总是重试

3. RetryTemplate提供了更为灵活的重试控制

  了解了重试策略,当我们使用RetryTemplate模式的时候,可以更加灵活的重试控制

@Configuration
@EnableRetry
public class RetryConfig {

    @Bean
    public RetryTemplate retryTemplate() {
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(3);

        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        backOffPolicy.setBackOffPeriod(1000);

        RetryTemplate retryTemplate = new RetryTemplate();
        retryTemplate.setRetryPolicy(retryPolicy);
        retryTemplate.setBackOffPolicy(backOffPolicy);

        return retryTemplate;
    }
}
 public Object executeWithRetry() throws Exception{
        return retryTemplate.execute(new RetryCallback<Object, Exception>() {
            @Override
            public Object doWithRetry(RetryContext context) throws Exception {
                // 这里放置可能会失败的操作
                // 例如,调用远程服务或执行数据库操作
                // ...

                // 模拟失败
                if (true) {
                    throw new RuntimeException("Operation failed");
                }

                // 如果成功,则返回结果
                return "success";
            }
        });
    }

  在Spring Boot项目中,通过集成Spring Retry模块,我们可以优雅地实现对第三方API调用的重试机制。通过@Retryable注解,我们能够很方便地在方法级别上添加重试策略。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1883261.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LinkedHashMap、TreeMap

LinkedHashMap&#xff1a; 有序、不重复、无索引&#xff0c;底层是双链表 TreeMap&#xff1a;底层基于红黑树&#xff0c;可以对键进行排序 默认排序&#xff1a;integer和string都是从小到大排序 例题&#xff1a;

基于SpringBoot扶农助农政策管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;…

Qt:7.QWidget属性介绍(cursor属性-光标形状、font属性-控件文本样式、tooltip属性-控件提示信息)

目录 一、cursor属性-光标形状&#xff1a; 1.1cursor属性介绍&#xff1a; 1.2获取当前光标形状——cursor()&#xff1a; 1.3 设置光标的形状——setCursor()&#xff1a; 1.4 设置自定义图片为光标&#xff1a; 二、font属性-控件文本样式&#xff1a; 2.1font属性介绍…

什么样的网工才是有前途的?

最近整个就业市场的变化&#xff0c;搞得人心惶惶。 可能很多朋友都在思考这样一个问题&#xff1a;现在做网工还有前途吗&#xff1f;什么样的网工才是有前途的&#xff1f;考HCIE认证还来得及吗&#xff1f; 作为网络工程师&#xff0c;该如何确保自己的职业发展方向正确&a…

光荚含羞草基因组-文献精读26

Haplotype-resolved genome of Mimosa bimucronata revealed insights into leaf movement and nitrogen fixation 光荚含羞草单倍型解析基因组揭示了叶片运动和固氮的相关机制 摘要 背景 光荚含羞草起源于热带美洲&#xff0c;具有独特的叶片运动特征&#xff0c;其运动速度…

C语言之进程的学习2

Env环境变量&#xff08;操作系统的全局变量&#xff09;

2024年7月1日 (周一) 叶子游戏新闻

老板键工具来唤去: 它可以为常用程序自定义快捷键&#xff0c;实现一键唤起、一键隐藏的 Windows 工具&#xff0c;并且支持窗口动态绑定快捷键&#xff08;无需设置自动实现&#xff09;。 喜马拉雅下载工具: 字面意思 《星刃》早期概念图分享 末世破败环境推主Genki分享了《星…

泛微E9开发 限制明细表列的值重复

限制明细表列的值重复 1、需求说明2、实现方法3、扩展知识点3.1 修改单个字段值&#xff08;不支持附件类型&#xff09;3.1.1 格式3.1.2 参数3.1.3 案例 3.2 获取明细行所有行标示3.2.1 格式3.2.2 参数说明 1、需求说明 限制明细表的“类型”字段&#xff0c;在同一个流程表单…

海康视频播放,包含h5和web插件

自行下载 海康开放平台 demo 都写得很清楚&#xff0c;不多描述 1.视频web插件 vue2写法&#xff0c;公共vue文件写法&#xff0c;调用文件即可 开始时需要以下配置&#xff0c;不知道的找对接平台数据的人&#xff0c;必须要&#xff0c;否则播不了 getParameterData: {po…

实施粘贴式导航_滚动事件

● 所谓的粘贴式导航&#xff0c;就是当我们滑动页面到某一个位置的时候&#xff0c;导航不会因为滑动而消失&#xff0c;会固定在页面的顶部&#xff0c;我们来看一下如何实现&#xff1b; ● 首先我们要获取我们想要滚动到哪一部分的时候让导航栏显示出来&#xff0c;这就需要…

【后端面试题】【中间件】【NoSQL】MongoDB的优点和分片机制

为什么要用MongoDB 两个关键&#xff1a;灵活性和横向扩展能力 MongoDB是灵活的文档模型&#xff0c;也就是说&#xff0c;如果预计我的数据可以被一个稳定的模型来描述&#xff0c;会倾向于使用MySQL等关系型数据库。而一旦我认为我的数据模型会经常变动&#xff0c;比如我很…

斩获大奖!移远通信以高算力智能模组产品,推动工业生产智能化发展

6月27日&#xff0c;在2024 MWC上海期间&#xff0c;由通信世界全媒体主办的2024信息通信业“新智推荐”优秀企业/方案获奖名单重磅发布。 作为全球领先的物联网整体解决方案供应商&#xff0c;移远通信凭借其丰富的高算力智能模组产品&#xff0c;以及相关方案在工业智能领域的…

RK3568驱动指南|第十五篇 I2C-第167章 I2C上拉电阻

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

HTML如何在图片上添加文字

HTML如何在图片上添加文字 当我们开发一个页面&#xff0c;插入图片时&#xff0c;需要有一组文字对图片进行描述。那么HTML中如何在图片上添加文字呢&#xff1f;这篇文章告诉你。 先让我们来看下效果图&#xff1a; 句子“这是一张夜空图片”被放置在了图片的左下角。 那么…

SpringBoot整合Solr进行搜索(简单)

SpringBoot整合Solr进行搜索 创建SpringBoot项目pom中加入Solr依赖配置 Solr创建实体编写一个简单的ID查询打印结果 参考文章 创建SpringBoot项目 这里基于aliyun提供的快速构建一个项目。我们这主要是整合Solr。 pom中加入Solr依赖 maven下载地址 pom中加入以下内容&#x…

Redis分布式集群部署

目录 一. 原理简述 二. 集群配置​​​​​​​ 2.1 环境准备 2.2 编译安装一个redis 2.3 创建集群 2.4 写入数据测试 实验一&#xff1a; 实验二&#xff1a; 实验三&#xff1a; 实验四&#xff1a; 添加节点 自动分配槽位 提升节点为master&#xff1a; 实验…

如果使用Outlook 2024出现问题

大家好&#xff0c;才是真的好。 很多企业使用Domino服务器当作POP/IMAP邮箱服务器来使用&#xff0c;虽然这不能发挥Domino最佳效能&#xff0c;但也不失为一种简单用法。 另一种企业则使用Domino仅作为应用app平台&#xff0c;邮箱早已迁移至O365或其他平台&#xff0c;他们…

安装和微调大模型(基于LLaMA-Factory)

打开终端&#xff08;在Unix或macOS上&#xff09;或命令提示符/Anaconda Prompt&#xff08;在Windows上&#xff09;。 创建一个名为lora的虚拟环境并指定Python版本为3.9。 https://github.com/echonoshy/cgft-llm/blob/master/llama-factory/README.mdGitHub - hiyouga/…

.net8 Syncfusion生成pdf/doc/xls/ppt最新版本

新建控制台程序 添加包Syncfusion.Pdf.Net.Core包&#xff0c;当前官方的版本号为26.1.39 直接上代码 Syncfusion.Pdf.PdfDocument pdfDocument new Syncfusion.Pdf.PdfDocument(); for (int i 1; i < 10; i) {var page pdfDocument.Pages.Add();PdfGraphics graphics…

学习笔记(linux高级编程)9

void pthread_cleanup_push(void (*routine)(void *)&#xff0c; void *arg); 功能&#xff1a;注册一个线程清理函数 参数&#xff0c;routine&#xff0c;线程清理函数的入口 arg&#xff0c;清理函数的参数。 返回值&#xff0c;无 void pthread_cleanup_pop(int execute)…