前言

今天分享干货,控制了篇幅,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. 别再用 offset 和 limit 分页了,性能太差!

    不需要担心数据库性能优化问题的日子已经一去不复返了. 随着时代的进步,随着野心勃勃的企业想要变成下一个 Facebook,随着为机器学习预测收集尽可能多数据的想法的出现. 作为开发人员,我们要不断地打 ...

  2. 【项目源码】JSP超市积分管理系统源码下载

    会员积分管理系统的目标是为中小规模的会员积分管理系统的目标是为中小规模的超市提供会员信息管理.会员积分管理以及积分兑换管理的具体解决方案. 网站和积分管理系统采用B/S结构,使用J2EE的技术开发完成 ...

  3. Web端上传数据到OSS

    阿里云文档:参考文献 更正第三点:用户带着从服务器获取的数据签名和文件上传到OSS,这样做可以保证安全性.减轻服务器负担. 1.操作步骤 ①新建Bucket ②创建后更改跨域设置 这一步是保证跨域请胯 ...

  4. Django-rest-framework框架——路由组件、认证权限频率

    @ 目录 一 路由Routers 1.1 使用方法 1.2 代码演示 1.2 视图集中附加action的声明 1.3 路由router形成URL的方式 认证权限频率 一 认证Authenticatio ...

  5. Python面试——基础面试题

    文章目录 1.Python 和 Java.PHP.C.C#.C++等其他语言的对比? C语言既有高级语言的特点,又具有汇编语言的特点,它是结构式语言.C语言应用指针:可以直接进行靠近硬件的操作,但是C ...

  6. Oracle:字符串的拼接、截取、查找、替换

    一.拼接:1.使用"||"来拼接字符串: select '拼接'||'字符串' as Str from dual; 2.使用concat(param1,param2)函数实现: s ...

  7. xgo多线程

    import threading import time #导入xgoedu from xgoedu import XGOEDU from xgolib import XGO #导入xgolib  # ...

  8. 2023_10_10_MYSQL_DAY_02_笔记

    2023_10_10_MYSQL_DAY_02_笔记 #在 FROM 子句中使用子查询 SELECT a.ename, a.sal, a.deptno, b.salavg FROM emp a, (S ...

  9. 【算法】游戏中的学习,使用c#面向对象特性控制游戏角色移动

    最近,小悦的生活像是一首繁忙的交响曲,每天忙得团团转,虽然她的日程安排得满满当当,但她并未感到充实.相反,她很少有时间陪伴家人,这让她感到有些遗憾.在周五的午后,小悦的哥哥突然打来电话,他的声音里充满 ...

  10. C#版字节跳动SDK - SKIT.FlurlHttpClient.ByteDance

    前言 在我们日常开发工作中对接第三方开放平台,找一款封装完善且全面的SDK能够大大的简化我们的开发难度和提高工作效率.今天给大家推荐一款C#开源.功能完善的字节跳动SDK:SKIT.FlurlHttp ...