网站首页 > 技术教程 正文
前言
今天分享干货,控制了篇幅,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框架还是挺实用的,但不是万能的。
优点是,简化了重试逻辑,提供了现成的重试策略,具备一定灵活性。
缺点,也很明显,生产环境使用有风险,比如在复杂场景下配置的策略有问题,有可能会导致无限重试,这个后果不用说大家也能想象。
所以,使用这个框架,一定要明确好场景再使用,我这里不推荐复杂场景下使用,因为君子不立于危墙之下。
好了,今天的知识点你学会了吗?
私信回复【retry】即可获取完整代码
猜你喜欢
- 2024-09-25 屡败屡战RETRY第六关关卡攻略 屡屡败屡战的意思
- 2024-09-25 基于redis实现的分布式队列 基于 redis 实现分布式锁是?
- 2024-09-25 .NET 使用 mysql 时 EnableRetryOnFailure() 函数的作用及注意事项
- 2024-09-25 新连载漫画大作导视(十月篇) 十日十月漫画作家
- 2024-09-25 基于guava的重试组件Guava-Retryer
- 2024-09-25 我是怎样得到AO3内容的 我是怎样得到ao3内容的英文
- 2024-09-25 Spring Boot 中使用 spring-retry 轻松解决重试
- 2024-09-25 Java重试利器之Guava-Retryer retry java
- 2024-09-25 springCloud负载均衡机制 springcloud负载均衡策略有哪些
- 2024-09-25 LabVIEW调用DLL中一、二级指针参数及打包exe运行异常的解决办法
你 发表评论:
欢迎- 05-1613步震撼淘宝大促闪光裂纹破墙立体字PS制作教程
- 05-16AI教程 | 绘制扁平的萌萌哒图标
- 05-160基础学平面设计所需了解的基础常识汇总
- 05-16自学平面设计需要多长时间?十六年职业设计总监告诉你
- 05-16平面设计都要学习哪些内容?
- 05-16李涛PS教程 高手之路PS教程 合成教程 —制作一个小星球
- 05-16Illustrator实例教程:制作炫酷的漩涡效果
- 05-16Illustrator实例教程:利用混合工具制作一朵炫酷的花
- 最近发表
- 标签列表
-
- sd分区 (65)
- raid5数据恢复 (81)
- 地址转换 (73)
- 手机存储卡根目录 (55)
- tcp端口 (74)
- project server (59)
- 双击ctrl (55)
- 鼠标 单击变双击 (67)
- debugview (59)
- 字符动画 (65)
- flushdns (57)
- ps复制快捷键 (57)
- 清除系统垃圾代码 (58)
- web服务器的架设 (67)
- 16进制转换 (69)
- xclient (55)
- ps源文件 (67)
- filezilla server (59)
- 句柄无效 (56)
- word页眉页脚设置 (59)
- ansys实例 (56)
- 6 1 3固件 (59)
- sqlserver2000挂起 (59)
- vm虚拟主机 (55)
- config (61)
本文暂时没有评论,来添加一个吧(●'◡'●)