SpringBoot 中使用 spring-retry 轻松解决重试

文章介绍了如何在SpringBoot应用中使用SpringRetry来实现自动重试机制,通过引入spring-boot-starter-aop和spring-retry依赖,启用@EnableRetry注解,并在方法上添加@Retryable注解来标记需要重试的操作。文章还详细讲解了@Retryable的配置参数,如异常类型、最大重试次数和重试间隔,并提到了重试耗尽后的回调方法@Recover的使用。此外,文章强调了基于AOP的重试机制不支持类内方法自调用以及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点击上方“Java基基”,选择“设为星标”

做积极的人,而不是积极废人!

每天 14:00 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:blog.csdn.net/qq_40065776/

article/details/129069455

8f12bd0616ba778350be09685633d736.png


在日常开发过程中,难免会与第三方接口发生交互,例如:短信发送、远程服务调用、争抢锁等场景,当正常调用发生异常时,例如:网络抖动,这些间歇性的异常在一段时候之后会自行恢复,程序为了更加健壮并且更不容易出现故障,需要重新触发业务操作,以防止间歇性的异常对程序照成的影响。

常用的重试策略,比如通过 while 循环手动重复调用或是通过 JDK/CGLib 动态代理的方式来进行重试。但是这种方法比较笨重,且对原有逻辑代码的入侵性比较大。

1、引入spring-retry

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

这里我们还引入了 aop 的依赖,因为 spring-retry 的原理就是基于 aop 来实现的

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

2、开启spring-retry

启动类上增加注解 @EnableRetry

@EnableRetry
@SpringBootApplication
public class AsurplusApplication {
    public static void main(String[] args) {
        SpringApplication.run(AsurplusApplication.class, args);
    }
}

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

3、@Retryable

在需要重试的方法上增加注解 @Retryable,表示该方法需要重试

@Component
public class TestRetry {

    int a = 0;

    @Retryable(value = {RuntimeException.class}, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
    public String test() {
        a++;
        System.out.println(a + " - " + System.currentTimeMillis());
        if (a < 10) {
            throw new RuntimeException("未满足条件");
        }
        return "执行成功";
    }

}

@Retryable 注解

  • value,可重试的异常类型。含义同include。默认为空(如果excludes也为空,则重试所有异常)

  • include:可重试的异常类型。默认为空(如果excludes也为空,则重试所有异常)

  • exclude:无需重试的异常类型。默认为空(如果includes也为空,则重试所有异常)

  • maxAttempts:最大重试次数(包括第一次失败),默认为3次

  • backoff:重试等待策略,下面会在@Backoff中介绍

  • recover:表示重试次数到达最大重试次数后的回调方法

@Backoff 注解

  • delay,重试之间的等待时间(以毫秒为单位)

  • maxDelay,重试之间的最大等待时间(以毫秒为单位)

  • multiplier,指定延迟的倍数

  • delayExpression,重试之间的等待时间表达式

  • maxDelayExpression,重试之间的最大等待时间表达式

  • multiplierExpression,指定延迟的倍数表达式

  • random,随机指定延迟时间

4、重试耗尽

当重试耗尽时,RetryOperations 可以将控制传递给另一个回调,即 RecoveryCallback。Spring-Retry 还提供了 @Recover 注解,用于 @Retryable 重试失败后处理方法。若不需要重试失败后的处理方法,则不写回调方法,重试耗尽后抛出异常。

@Recover
public String recoverTest(RuntimeException e) {
    return "回调方法-" + e.getMessage();
}
  • 方法的返回值必须与 @Retryable 方法一致

  • 方法的第一个参数,必须是 Throwable 类型的,建议是与 @Retryable 配置的异常一致,其他的参数,需要哪个参数,写进去就可以了(@Recover 方法中有的)

  • 该回调方法与重试方法写在同一个实现类里面

若同一个实现类中有多个回调方法,我们需要使用 recover 属性指定回调的方法名

@Component
public class TestRetry {

    int a = 0;

    @Retryable(recover = "recoverTest1", value = {RuntimeException.class}, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
    public String test() {
        a++;
        System.out.println(a + " - " + System.currentTimeMillis());
        if (a < 10) {
            throw new RuntimeException("未满足条件");
        }
        return "执行成功";
    }

    @Recover
    public String recoverTest(RuntimeException e) {
        return "回调方法-" + e.getMessage();
    }

    @Recover
    public String recoverTest1(RuntimeException e) {
        return "回调方法1-" + e.getMessage();
    }
}

指定了回调方法为 recoverTest1

5、注意事项

  • 由于是基于 AOP 实现,所以不支持类里自调用方法

  • 如果重试失败需要给 @Recover 注解的方法做后续处理,那这个重试的方法不能有返回值,只能是 void

  • 方法内不能使用 try catch,只能往外抛异常

  • @Recover 注解来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中),此注解注释的方法参数一定要是 @Retryable 抛出的异常,否则无法识别,可以在该方法中进行日志处理。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

ac80d83b7d1a58663cad918f5182a353.png

已在知识星球更新源码解析如下:

f2f14e9d0a3b1329fbdec065f0e05080.jpeg

6e1efd7d9e0af086e29a07eb1cb7960b.jpeg

8dfb586ff10f17ee2f72d735f6ceab1e.jpeg

3a5d58ffee054eeeb58f98985b25f4b5.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值