首页 > 其他分享 >5分钟攻略Spring-Retry框架实现经典重试场景

5分钟攻略Spring-Retry框架实现经典重试场景

时间:2023-12-22 09:34:51浏览次数:22  
标签:Retry Spring springframework 重试 retry import org 异常

前言

今天分享干货,控制了篇幅,5分钟内就能看完学会。

主题是Spring-Retry框架的应用,做了一个很清晰的案例,代码可下载自测。

框架介绍

Spring-Retry框架是Spring自带的功能,具备间隔重试包含异常排除异常控制重试频率等特点,是项目开发中很实用的一种框架。

本篇所用框架的版本如下:

技术 版本
Java 17
SpringBoot 3.2
Spring-retry 2.0.4

正文

1、引入依赖

坑点:需要引入AOP,否则会抛异常。

<!-- Spring-Retry -->
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<!-- Spring-AOP -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、启动类注解

坑点:很容易一时疏忽忘记启动类开启@EnableRetry,大家别忘了哦。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;

@SpringBootApplication
@EnableRetry
public class SpringRetryDemoApplication {

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

}

3、模拟发短信

我们模拟一个发短信功能,根据随机数分别作为成功、失败、抛出各种异常的入口。

这里抛出几种异常的目的,是为了后面演示出重试注解参数产生的效果。

import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 短信服务工具类
 * </p>
 *
 * @author 程序员济癫
 * @since 2023-12-21 09:40
 */
@Slf4j
public class SmsUtil {

   /**
    * 发送短信
    */
   public static boolean sendSms() {

      // 使用随机数模拟重试场景
      int num = RandomUtil.randomInt(4);
      log.info("[SmsUtil][sendSms]>>>> random num = {}", num);

      return switch (num) {
         case 0 ->
               // 模拟发生参数异常
               throw new IllegalArgumentException("参数有误!");
         case 1 ->
               // 模拟发生数组越界异常
               throw new ArrayIndexOutOfBoundsException("数组越界!");
         case 2 ->
               // 模拟成功
               true;
         case 3 ->
               // 模拟发生空指针界异常
               throw new NullPointerException();
         default ->
               // 未成功则返回false
               false;
      };

   }
}

4、Retry应用

我们单独写一个用于重试调用的组件类,用于业务类调用。

import com.example.springretrydemo.util.SmsUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * <p>
 * 重试组件
 * </p>
 *
 * @author 程序员济癫
 * @since 2023-12-21 09:43
 */
@Slf4j
@Component
public class RetryComponent {

   /**
    * 重试机制发送短信
    */
   @Retryable(
         retryFor = {IllegalArgumentException.class, ArrayIndexOutOfBoundsException.class},
         noRetryFor = {NullPointerException.class},
         maxAttempts = 4,
         backoff = @Backoff(delay = 2000L, multiplier = 2)
   )
   public boolean sendSmsRetry() {

      log.info("[RetryComponent][sendSmsRetry]>>>> 当前时间:{}", getNowTime());
      return SmsUtil.sendSms();
   }

   /**
    * 兜底方法,规则:
    *        1、超出了最大重试次数;
    *        2、抛出了不进行重试的异常;
    */
   @Recover
   public boolean recover() {
      log.info("[RetryComponent][recover]>>>> 短信发送次数过多,请稍后重试!");
      return false;
   }

   /**
    * 获取当前时间
    */
   private String getNowTime() {

      return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
   }
}

@Retryable注解参数说明:

  • retryFor:此参数包含的异常会触发重试机制,多个异常则以数组形式定义。
  • noRetryFor:此参数包含的异常不会触发重试机制,多个异常则以数组形式定义。
  • maxAttempts:重试最大次数,不定义则默认3次。
  • backoff:定义补偿机制,delay-延迟时间(s),multiplier-重试时间的倍数(比如设置为2,重试4次的话,补偿机制就是分别间隔2s、4s、8s做重试)

@Recover注解说明:用于兜底,当 超出了最大重试次数抛出了不进行重试的异常 时,直接执行该注解声明的兜底方法。

PS:顺便提一句,如果是 SpringBoot2.x 的版本,这里@Retryable注解的retryFor参数对应的是includenoRetryFor参数对应的是exclude,可以直接点进去看源码便一目了然。


5、JunitTest测试

我们编写一个Junit测试类来测试重试的效果,并打印出结果信息。

import com.example.springretrydemo.retry.RetryComponent;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@Slf4j
@SpringBootTest
class SpringRetryDemoApplicationTests {

   @Autowired
   private RetryComponent retryComponent;

   @Test
   void sendSmsTest() {
      boolean ret = retryComponent.sendSmsRetry();
      log.info("sendSmsTest result = {}", ret);
   }

}

6、效果

第1次测试时,可以看到,随机数刚好都是1,走的是数组越界异常。

而这个异常在retryFor中定义了,所以执行了4次,直到结束,最后进入了兜底方法。

同时,可以看到,执行4次的频率也和预想一样是2s、4s、8s。

image

第2次测试时,可以看到,随机数是3,走的是空指针异常。

而这个异常在noRetryFor中定义了,所以接下来直接进入了兜底方法。

image

第3次测试时,可以看到,第一次随机数是0,走的参数异常,在retryFor中,所以2s后继续重试。

然后随机数是2,表示业务成功,所以直接返回了true。

这个场景就很像大家经常遇见的补偿操作,第一次发生异常失败,第二次重试后又成功了。

image

总结

Spring-retry框架还是挺实用的,但不是万能的。

优点是,简化了重试逻辑,提供了现成的重试策略,具备一定灵活性。

缺点,也很明显,生产环境使用有风险,比如在复杂场景下配置的策略有问题,有可能会导致无限重试,这个后果不用说大家也能想象。

所以,使用这个框架,一定要明确好场景再使用,我这里不推荐复杂场景下使用,因为君子不立于危墙之下

好了,今天的知识点你学会了吗?

完整代码:戳这里 --> Gitee


喜欢请点赞+关注↑↑↑,持续分享干货哦~

标签:Retry,Spring,springframework,重试,retry,import,org,异常
From: https://www.cnblogs.com/fulongyuanjushi/p/17920410.html

相关文章

  • Spring-IOC
     1.前言1) 框架:spring的本质就是一个容器,放java对象的容器,java对象在spring容器中也叫做bean对象。项目启动的时候,把bean对象放到IOC容器中,当需要使用对象的时候,直接从容器中拿出来使用。2) 框架作用:提高开发效率;增强可重用性;提供编......
  • 【SpringBootWeb入门-17】Mybatis-基础操作-动态SQL
    1、章节回顾上一篇文章我们讲解完了Mybatis基础操作,本篇继续学习Mybatis中非常重要的功能:动态SQL。什么是动态SQL:随着用户的输入或外部条件的变化而变化的SQL语句,我们称为动态SQL。简单说SQL语句不是固定的,是动态变化的。就拿我们上一篇所提到的根据条件来查询员工的SQL语句来......
  • Spring Boot学习随笔- 拦截器实现和配置(HandlerInterceptor、addInterceptors)、jar包
    学习视频:【编程不良人】2021年SpringBoot最新最全教程第十三章、拦截器拦截器:Interceptor拦截中断类似于javaweb中的Filter,不过没有Filter那么强大作用SpringMVC的拦截器是一种用于在请求处理过程中进行预处理和后处理的机制。拦截器可以在请求到达控制器之前和......
  • Spring mvc中前后端数据交互的方式
    现在IT行业ssm框架用的还是挺多的,今天给大家分享一下springmvc中前后的数据交互的方式:后端➡前端在SpringMVC中这主要通过Model将数据从后端传送到前端,一般的写法为:@RequestMapping(value="/index",method=RequestMethod.POST)publicStringindex(Modelmodel){String......
  • 搭建springcloud注册中心eureka以及admin监控
    现在springcloud微服务是当下盛行的主流框架,我们可以通过eureka实现服务监控和预警。接下来是项目搭建的主要步骤一、搭建eureka-server注册中心注意点有三个,分别是1.pom导入依赖(下面是完整的pom文件):springboot、eureka-server、springcloud<?xmlversion="1.0"encoding="UTF-......
  • 如何新建SpringBoot2.7.X项目
    新版的idea在创建SpringBoot项目时最低的JDK都需要选择jdk17,可是我的本地只有jdk8,通过创建maven工程,然后在pom中手动填写相关依赖等信息来创建项目,pom文件内容(官网copy的)<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-......
  • SpringBoot原理
    配置SpringBoot中支持三种格式的配置文件.properties.yml.yaml虽然Springboot支持多种文件配置,但是通常在项目开发中,我们一般推荐使用yml文件配置优先级在SpringBoot项目中,常见的属性配置有5种,3种配置文件加上两种外部的配置,生效优先级SrpingBoot配置优先级(低->高):1......
  • Spring Retry使用小结
    目录1、背景2、使用步骤2.1、pom.xml中引入相关依赖2.2、启用@Retryable2.3、在响应方法上加上注解1、背景日常开发中经常会下发接口回调通知失败、远程调用失败等等,这些错误可能是因为网络波动造成的,等待过后重处理就能成功。通常来说,会用try/catch,while循环之类的语法来进行重......
  • Spring Validation使用小结
    目录1、背景2、常用注解2.1、BeanValidation2.0注解2.1.1、校验空值2.1.2、校验大小2.1.3、校验布尔值2.1.4、校验日期和时间2.1.5、正则表达式2.1.5.1、验证IP地址2.1.5.1、验证手机号码3、使用3.1、当方法入参为@PathVariable、@RequestParam注解的简单参数时,需要在Cont......
  • Spring框架的事务管理
    引言事务管理是企业应用程序中不可或缺的一个方面,它确保数据的一致性和完整性。Spring框架提供了一个灵活的事务管理抽象,它可以透明地工作在不同的事务管理API之上。事务管理的基本概念在深入Spring的事务管理之前,让我们回顾几个关键概念:事务(Transaction):一系列的动作,它们被视为一个......