前言

今天分享干货,控制了篇幅,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。

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

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

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

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

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

总结

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

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

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

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

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

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


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

5分钟攻略Spring-Retry框架实现经典重试场景的更多相关文章

  1. 【三维地图】开发攻略 —— 详解“GeoJSON”技术和应用场景

    GeoJSON ,一个用于存储地理信息的数据格式.GoeJSON对象可以表示几何.特征或特征集合,支持:点.线.面.多点.多线.多面和几何集合.在基于平面地图,三维地图中都需要用到的一种数据类型. 由 ...

  2. Spring retry实践

    在开发中,重试是一个经常使用的手段.比如MQ发送消息失败,会采取重试手段,比如工程中使用RPC请求外部服务,可能因为网络波动出现超时而采取重试手段......可以看见重试操作是非常常见的一种处理问题, ...

  3. Spring Retry 重试

    重试的使用场景比较多,比如调用远程服务时,由于网络或者服务端响应慢导致调用超时,此时可以多重试几次.用定时任务也可以实现重试的效果,但比较麻烦,用Spring Retry的话一个注解搞定所有.话不多说 ...

  4. 异常重试框架Spring Retry实践

    前期准备在Maven项目中添加Spring Retry和切面的依赖 POM: <!-- Spring Retry --> <dependency> <groupId> ...

  5. Spring异常重试框架Spring Retry

    Spring Retry支持集成到Spring或者Spring Boot项目中,而它支持AOP的切面注入写法,所以在引入时必须引入aspectjweaver.jar包. 快速集成的代码样例: @Con ...

  6. Java - 框架之 SpringBoot 攻略day01

          Spring-Boot 攻略 day01 spring-boot   一. 基本配置加运行   1. 导入配置文件(pom.xml 文件中)   <parent> <gr ...

  7. Spring框架中一个有用的小组件:Spring Retry

    1.概述 Spring Retry 是Spring框架中的一个组件, 它提供了自动重新调用失败操作的能力.这在错误可能是暂时发生的(如瞬时网络故障)的情况下很有帮助. 在本文中,我们将看到使用Spri ...

  8. 自己动手实践 spring retry 重试框架

    前序 马上过年了,预祝大家,新年快乐,少写bug 什么是spring retry? spring retry是从spring batch独立出来的一个能功能,主要实现了重试和熔断. 什么时候用? 远程 ...

  9. 简单易懂的现代魔法——Play Framework攻略1

    哇哈哈,寒假结束啦,于是我又开新坑了....这次的主角可是大名鼎鼎的Play Framework!!那么闲话少说,开始攻略吧! 1.什么是Play Framework? 大名鼎鼎的play frame ...

  10. 【JAVA EE企业级开发四步走完全攻略】

    本文是J2EE企业级开发四步走完全攻略索引,因内容比较广泛,涉及整个JAVA EE开发相关知识,这是一个长期的计划,单个发blog比较零散,所以整理此索引,决定以后每发一季JAVA EE blog后会 ...

随机推荐

  1. 聊聊HuggingFace如何处理大模型下海量数据集

    翻译自: Big data? Datasets to the rescue! 如今,使用大GB的数据集并不罕见,特别是从头开始预训练像BERT或GPT-2这样的Tranformer模型.在这样的情况下 ...

  2. 在 Android Studio Java 项目里混合 Kotlin 编程

    首先,先搞明白一个概念,这里的 Java 混合 Kotlin 是指文件层级的混合,即 Java 代码还是写在 .java 文件中,Kotlin 代码还是写在 .kt 文件中,只不过是可以在 Java ...

  3. .NET反编译神器ILSpy怎么用?

    前言 上一篇文章我们介绍了4款免费且实用的.NET反编译工具,这篇文章主要来说说ILSpy这个工具该如何安装和使用. ILSpy ILSpy是一款免费.开源的 .NET 反编译工具,能够将已编译的 . ...

  4. DHCP是什么

    DHCP 1. DHCP是什么 协议,一种应用层的网络协议,他可以动态地分配网络中的IP地址和其他网络配置的参数以及网络设备,通俗一点讲,每台设备的IP地址,子网掩码,网关等网络参数信息都是由他来完成 ...

  5. 使用ensp搭建路由拓扑,并使用isis协议实现网络互通实操

    转载请注明出处: 1.通过拓扑搭建如下拓扑: 其中R7.R8为L1,R6为L1/2,R9为L2. 2.配置isis实现网络互通 R7配置如下: [Huawei]isis 1 [Huawei-isis- ...

  6. 第五周单元测验题英语教学与互联网 mooc

    第五周单元测验题 返回 本次得分为:16.00/20.00, 本次测试的提交时间为:2020-08-30, 如果你认为本次测试成绩不理想,你可以选择 再做一次 . 1 单选(2分) 从评价的主体来看, ...

  7. linux的认知与基本命令

    一.linux的了解 1. 什么是Linux?       a,Linux是一种免费使用和自由传播的类UNIX操作系统,其内核由林纳斯·本纳第克特·托瓦兹于1991年10月5日首次发布.它主要受到Mi ...

  8. Java虚拟机(JVM):第三幕:自动内存管理 - 垃圾收集器与内存分配策略

    前言:Java与C++之间有一堵高墙,主要是有内存动态分配和垃圾收集技术组成的.墙外的人想要进来,墙内的人想要出去. 一.概述 每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的.内存的分配和 ...

  9. ubuntu 20.1 (linux) 下软件安装教程(基本上都是使用命令行安装)

    一.node 1. 安装教程 # 第二步,添加源后安装 需要什么版本直接替换后面的数字即可,如果需要21,直接将20替换为21就可以了 curl -sL https://deb.nodesource. ...

  10. tunm, 一种对标JSON的二进制数据协议

    Tunm simple binary proto 一种对标JSON的二进制数据协议 支持的数据类型 基本支持的类型 "u8", "i8", "u16& ...