5分钟攻略Spring-Retry框架实现经典重试场景
前言
今天分享干货,控制了篇幅,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参数对应的是include,noRetryFor参数对应的是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框架实现经典重试场景的更多相关文章
- 【三维地图】开发攻略 —— 详解“GeoJSON”技术和应用场景
GeoJSON ,一个用于存储地理信息的数据格式.GoeJSON对象可以表示几何.特征或特征集合,支持:点.线.面.多点.多线.多面和几何集合.在基于平面地图,三维地图中都需要用到的一种数据类型. 由 ...
- Spring retry实践
在开发中,重试是一个经常使用的手段.比如MQ发送消息失败,会采取重试手段,比如工程中使用RPC请求外部服务,可能因为网络波动出现超时而采取重试手段......可以看见重试操作是非常常见的一种处理问题, ...
- Spring Retry 重试
重试的使用场景比较多,比如调用远程服务时,由于网络或者服务端响应慢导致调用超时,此时可以多重试几次.用定时任务也可以实现重试的效果,但比较麻烦,用Spring Retry的话一个注解搞定所有.话不多说 ...
- 异常重试框架Spring Retry实践
前期准备在Maven项目中添加Spring Retry和切面的依赖 POM: <!-- Spring Retry --> <dependency> <groupId> ...
- Spring异常重试框架Spring Retry
Spring Retry支持集成到Spring或者Spring Boot项目中,而它支持AOP的切面注入写法,所以在引入时必须引入aspectjweaver.jar包. 快速集成的代码样例: @Con ...
- Java - 框架之 SpringBoot 攻略day01
Spring-Boot 攻略 day01 spring-boot 一. 基本配置加运行 1. 导入配置文件(pom.xml 文件中) <parent> <gr ...
- Spring框架中一个有用的小组件:Spring Retry
1.概述 Spring Retry 是Spring框架中的一个组件, 它提供了自动重新调用失败操作的能力.这在错误可能是暂时发生的(如瞬时网络故障)的情况下很有帮助. 在本文中,我们将看到使用Spri ...
- 自己动手实践 spring retry 重试框架
前序 马上过年了,预祝大家,新年快乐,少写bug 什么是spring retry? spring retry是从spring batch独立出来的一个能功能,主要实现了重试和熔断. 什么时候用? 远程 ...
- 简单易懂的现代魔法——Play Framework攻略1
哇哈哈,寒假结束啦,于是我又开新坑了....这次的主角可是大名鼎鼎的Play Framework!!那么闲话少说,开始攻略吧! 1.什么是Play Framework? 大名鼎鼎的play frame ...
- 【JAVA EE企业级开发四步走完全攻略】
本文是J2EE企业级开发四步走完全攻略索引,因内容比较广泛,涉及整个JAVA EE开发相关知识,这是一个长期的计划,单个发blog比较零散,所以整理此索引,决定以后每发一季JAVA EE blog后会 ...
随机推荐
- Java下载多个网络文件并打成压缩包
需求:浏览器访问后台的http地址后,后台将多个网络文件打成压缩包返回给浏览器,用户可以通过浏览器直接下载压缩包. 实现: 根据文件链接把文件下载下来并且转成字节码 ,代码: package com ...
- tomcat配置域名绑定项目
有时候我们需要根据访问的不同域名,对应tomcat中不同的项目例如:一个网站同时做了两套,pc版和手机版.手机版对应的域名是m.we-going.com,就需要在tomcat配置文件中加入以下代码:& ...
- 【火坑】一切从TimeSpan说起
小编在编写WPF程序时,需要做一个判断:定时使用Modbus协议使用Quartz.net 定时任务读取设备中的数据,同时也使用定时任务判断是否长时间获取不到数据的情况,如果程序中超过一分钟没有获取到数 ...
- SpringCloud搭建保姆级教程
一.搭建服务注册与发现中⼼ 使⽤Spring Cloud Netflix 中的 Eureka 搭建服务注册与发现中⼼ 1.创建SpringBoot应用添加依赖 1.spring web 2.eurek ...
- 我的 Windows 文件管理哲学
前言 作为一个不合格的 Geek,我经常面临把 Windows 弄崩溃的尴尬处境,我的系统因此重装了一遍又一遍--不过在一次次的重装中,我逐渐总结出了于我个人而言行之有效的文件管理哲学,在此略做总 ...
- k8s1.25版本上实践 Ingress-nginx
背景: 领导要求的最新最新版本k8s...使用ingress-nginx 对外暴露内部服务 环境 节点 master worker 主机/ip calico-master01/192.168.195. ...
- Python基础——函数的理解、函数对象、函数嵌套、闭包函数、及其应用
文章目录 函数也是变量 可以赋值 可以当做函数当做参数传给另外一个函数 可以当做函数当做另外一个函数的返回值 可以当做容器类型的一个元素 函数对象应用示范 原始版 修正版 函数嵌套 函数的嵌套调用 函 ...
- 基于 ACK Serverless 解锁你家萌宠的 AI 形象
基于 ACK Serverless 解锁你家萌宠的 AI 形象详情 1. 计费说明 必看!!必看!!必看!! 本实验为付费体验,需要消耗账号费用.体验后若不再需要使用,请及时释放资源,避免持 ...
- C#堆排序算法
前言 堆排序是一种高效的排序算法,基于二叉堆数据结构实现.它具有稳定性.时间复杂度为O(nlogn)和空间复杂度为O(1)的特点. 堆排序实现原理 构建最大堆:将待排序数组构建成一个最大堆,即满足父节 ...
- OTOCI 题解
OTOCI 题目大意 给定 \(n\) 个带权的点,需要进行四种操作:查询两点连通性:加边:修改点权:查询两点路径的权值和. 思路分析 首先观察题目,我们会发现,在所有的操作结束后,所有的点构成一个森 ...