Spring的@Retryable和@Recover注解详解

Spring的@Retryable和@Recover注解详解

1. 简介

两个注解一般配合使用,通常用于解决由于网络、数据库、文件系统等原因导致的临时性错误,以提高应用的健壮性和可用性。

  • @Retryable@Recover是Spring Framework中的注解,用于支持在方法执行期间发生异常时的重试和恢复操作。
  • @Retryable注解用于标记方法,在方法执行期间发生异常时进行重试。重试行为可以使用Spring Retry框架提供的默认策略或自定义策略来定义。我们可以指定要重试的异常类型以及最大重试次数和重试间隔等参数。
  • @Recover注解用于标记一个恢复方法,在最终重试失败后执行该方法,降级处理。恢复方法应尽量具有与重试方法相同的参数和返回类型(提一嘴:两个方法的返回值类型必须相同,捕获异常类型和入参可以不同,后面给出实例),并且应在同一类中声明。如果未指定恢复方法,则重试失败后将抛出最后一次异常。

2. 实例:分母=0异常,导致重试(所有实例中fenzi=5,fenmu=0)

想要使用这两个注解,首先需引入依赖spring-retry,再启动类上添加注解@EnableRetry

    /*** 
     * @description: 测试重试和恢复注解,入参写死,fenzi=5, fenmu=0 
     * @param:  
     * @return:  
     * @author name silk
     * @date: 2024/1/30 21:11
     */
    @GetMapping("/retry")
    public String testRetryableAndRecover() {
        return testService.testRetryable(5, 0);
    }

2.1 重试方法,恢复方法有一致的入参类型、返回值类型;重试方法抛出异常与恢复方法异常类型一致;(成功)

    /***
     * @description:  测试注解@Retryable, 重试方法
     * @param: fenzi fenmu
     * @return:
     * @author name silk
     * @date: 2024/1/30 19:51
     */
    @Retryable(value = Exception.class, maxAttempts = 3)
    public String testRetryable(int fenzi, int fenmu) {
        int res;
        res = fenzi / fenmu;
        return "the calculate result is : " + res;
    }

    /***
     * @description: 测试恢复方法,降级处理
     * @param: e fenzi fenmu
     * @return:
     * @author name silk
     * @date: 2024/1/30 19:51
     */
    @Recover
    public String testRecover(Exception e, int fenzi, int fenmu) {
        log.info("调用恢复方法,做降级处理...");
        return "downgrade process over.";
    }

在这里插入图片描述

在上面的示例中,testRetryable()方法标记为重试,当Exception异常发生时最多重试3次。如果在最终重试失败后,testRetryable()方法将调用testRecover()方法进行恢复操作,并将最后一次重试的异常作为参数传递给testRecover()方法。

2.2 重试方法,恢复方法有一致的返回值类型;入参类型、异常类型不一致;(成功)

/***
     * @description:  测试注解@Retryable, 重试方法
     * @param: fenzi fenmu
     * @return:
     * @author name silk
     * @date: 2024/1/30 19:51
     */
    @Retryable(value = Exception.class, maxAttempts = 3)
    public String testRetryable(int fenzi, int fenmu) {
        int res;
        res = fenzi / fenmu;
        return "the calculate result is : " + res;
    }

    /***
     * @description: 测试恢复方法,降级处理
     * @param: e fenzi fenmu
     * @return:
     * @author name silk
     * @date: 2024/1/30 19:51
     */
    @Recover
    public String testRecover(ArithmeticException e) {
        log.info("调用恢复方法,做降级处理...");
        return "downgrade process over.";
    }

在这里插入图片描述
根据上述实例看,虽然实例2这种情况能够成功,但是建议开发过程中最好按照第一张情况各参数保持一致。

2.3 扩展:一个类中有多个@Recover和@Retryable怎么区分

如果一个类中有多个方法标记了@Retryable@Recover注解,我们可以通过value属性来区分它们。value属性允许指定一个异常类型的数组,以区分在方法执行期间抛出的不同异常类型。

@Service
public class TestService {
 
    @Retryable(value = {IOException.class})
    public void methodA() throws IOException {
        // Some code that may throw an IOException
    }
 
    @Recover
    public void recoverA(IOException e) {
        // Recovery logic for methodA() goes here
    }
 
    @Retryable(value = {NullPointerException.class})
    public void methodB() throws NullPointerException {
        // Some code that may throw a NullPointerException
    }
 
    @Recover
    public void recoverB(NullPointerException e) {
        // Recovery logic for methodB() goes here
    }
}

在上面的示例中,methodA()methodB()方法都标记为@Retryable注解,以便在抛出IOExceptionNullPointerException异常时进行重试。然后对于每个方法,都定义了一个恢复方法recoverA()recoverB(),分别提供特定于该方法的恢复逻辑。由于每个方法都在@Retryable注解的value属性中指定了不同的异常类型,因此Spring框架可以区分它们,并在适当的时候调用相应的方法。

2.4 扩展:如果上述情况的异常类型也一致怎么区分

如果多个方法在抛出相同的异常时都需要进行重试和恢复操作,我们可以在每个方法上使用相同的@Retryable@Recover注解。在这种情况下,Spring框架会自动根据需要调用相应的恢复方法。

@Recover注解标记的恢复方法中,可以通过方法的参数获取抛出异常的方法和异常信息。具体来说,@Recover方法可以接受与@Retryable注解标记的方法相同的参数,以便在恢复操作中访问异常信息和方法参数。

/***
     * @description:  测试注解@Retryable, 重试方法
     * @param: fenzi fenmu
     * @return:
     * @author name silk
     * @date: 2024/1/30 19:51
     */
    @Retryable(value = Exception.class, maxAttempts = 3)
    public String testRetryable(Integer fenzi, Integer fenmu) {
        Integer res;
        res = fenzi / fenmu;
        return "the calculate result is : " + res;
    }

    @Retryable(value = Exception.class, maxAttempts = 3)
    public String testRetryable(String fenzi, String fenmu) {
        Integer res;
        res = Integer.getInteger(fenzi) / Integer.parseInt(fenmu);
        return "the calculate result is : " + res;
    }

    /***
     * @description: 测试恢复方法,降级处理
     * @param: e fenzi fenmu
     * @return:
     * @author name silk
     * @date: 2024/1/30 19:51
     */
    @Recover
    public String testRecover(Exception e, Object fenzi, Object fenmu) {
        if (fenzi instanceof Integer) {
            log.info("重试方法入参类型是Integer,调用恢复方法,做降级处理...");
            return "integer === downgrade process over.";
        } else if (fenzi instanceof String) {
            log.info("重试方法入参类型是String,调用恢复方法,做降级处理...");
            return "string === downgrade process over.";
        }
        log.info("调用恢复方法,做降级处理...");
        return "downgrade process over.";
    }

在这里插入图片描述

在上面的示例中,methodA()methodB()方法都标记为@Retryable注解,以便在抛出Exception异常时进行重试。在@Recover注解标记的恢复方法中,可以通过方法的参数访问抛出异常的方法和方法参数。在上述示例中,我们检查第一个参数的类型以确定是哪个方法抛出了异常,从而提供相应的恢复逻辑。

3. 其他

(1)@Retryablebackoff参数定义了在重试操作之间使用的退避策略,目前支持5种策略:固定间隔退避策略、指数退避策略,随机间隔退避策略、指数退避策略(带有最大退避时间)、自定义退避策略。其中要自定义一个退避策略类,需要实现org.springframework.retry.backoff.BackOffPolicy接口,并实现其backOff()方法,这里不展开介绍了。
(2)最后需要注意,使用@Retryable注解会增加应用的复杂度,因为需要处理异常、定义退避策略等。在使用时需要权衡好可用性、性能和代码的复杂度,并根据具体的场景进行选择。

  • 28
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring @Retryable注解是一种在Spring框架中实现重试机制的解决方案。这个解决方案的主要思想是在方法发生异常时,让这个方法重新执行一次或多次,直到方法成功执行为止。这个方案可以让开发者在开发过程中减少一定的错误处理代码的编写,同时还可以增加系统的可靠性和鲁棒性。 使用Spring @Retryable注解的方法必须满足一定的条件,首先他必须存在于一个Spring管理的Bean中,其次必须有异常抛出。@Retryable注解可以指定重试的次数,每次重试间隔时间,重试的异常条件等等。这些参数可以根据开发者的需要进行深度定制,以实现更加灵活的重试行为。 @Retryable注解的处理方式是在Spring框架中通过AOP(面向切面编程)来进行的。具体的实现方式是,在AOP中拦截所有的方法调用,当被拦截的方法抛出指定的异常时,AOP会将这个异常交给重试拦截器进行处理,在处理过程中,重试拦截器会根据开发者指定的参数进行重试操作,并在重试次数达到上限后将异常抛回给方法调用者。 总的来说,Spring @Retryable注解提供了一种简单有效的处理异常情况的解决方案。在实际开发过程中,经常会遇到一些类似网络延迟、数据库访问失败等问题,这些问题往往需要程序员进行手动处理,而使用@Retryable注解可以让我们简化这种操作,提高程序的鲁棒性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值