前言

今天分享干货,控制了篇幅,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. CodeForces 1343D Constant Palindrome Sum

    题意 多组样例 给一个长度为\(n\)(\(n\)一定为偶数)的数组\(a[]\),给一个正整数\(k\),保证数组内元素为小于等于\(k\)的正整数,你可以每次将数组的一个元素变为小于等于\(k\) ...

  2. Mac m2使用实现微信小程序抓包

    Mac m2使用实现微信小程序抓包 最近换了MacBook Pro,芯片是M2 Pro,很多东西跟windows是不一样的,所以重新配置相应环境,这里介绍一下微信小程序抓包的方法. 使用burp+pr ...

  3. KRPANO资源分析工具下载VR-FACTORY全景图

    示:目前分析工具中的全景图下载功能将被极速全景图下载大师替代,相比分析工具,极速全景图下载大师支持更多的网站(包括各类KRPano全景网站,和百度街景) 详细可以查看如下的链接: 极速全景图下载大师官 ...

  4. Java爬虫实战系列2——动手写爬虫初体验

    在上面的章节中,我们介绍了几个目前比较活跃的Java爬虫框架.在今天的章节中,我们会参考开源爬虫框架,开发我们自己的Java爬虫软件. 首先,我们下载本章节要使用到的源代码,本章节主要提供了基于HTT ...

  5. Dubbo3应用开发—协议(Dubbo协议、REST协议 、gRPC协议、Triple协议)

    协议 协议简介 什么是协议 Client(Consumer端)与Server(Provider端)在传输数据时双方的约定. Dubbo3中常见的协议 1.dubbo协议[前面文章中使用的都是dubbo ...

  6. it 作形式主语:It's no good doing sth.

    It's no good doing sth. 这个 句型其实是一个省 略介词 in 的句型,完整形式是 It's no good in doing sth. 其中, good 是形容词,和介词 in ...

  7. 【matplotlib 实战】--直方图

    直方图,又称质量分布图,用于表示数据的分布情况,是一种常见的统计图表. 一般用横轴表示数据区间,纵轴表示分布情况,柱子越高,则落在该区间的数量越大.构建直方图时,首先首先就是对数据划分区间,通俗的说即 ...

  8. Gitlab Server

    Gitlab 基本概述 1.什么是Gitlab ? Gitlab是一个开源分布式的版本控制系统. Ruby语言开发完成. Gitlab主要实现的功能.管理项目源代码.对源代码进行版本控制.以及代码复用 ...

  9. CF1190C Tokitsukaze and Duel

    搬运一下本喵的 lg 博客 qwq 详细讲一下如何判定后手能否获胜,对其他题解做个补充.(蒟蒻的我想了好久来着 此题的关键点在于可以重复上一个人的操作使局面保持不变. 考虑先手的获胜条件,由上一段可知 ...

  10. 天上掉 Pizza

    实在不知道错哪了... 对着 std 检查了好几遍了QAQ 题解见注释(不过估计题解也是错的,不然为什么写错啊QAQ #include<bits/stdc++.h> using names ...