Spring Retry框架的使用教程

Spring Retry是Spring提供的重试机制,它支持注解方式进行配置,可以做到代码无浸入的重试操作。它的使用也很简单,我们先了解一下Spring Retry的基础概念。

一、基础概念:

String Retry支持普通方式使用和注解方式使用(下文中会展示写法)。我们重点说一下注解方式使用,这里主要设计到三个注解,具体如下:

  • @EnableRetry :添加在启动类上,表示开启重试。

  • @Retryable:添加在需要重试的方法上,该方法在发生异常时,会进行重试。

  • @Recover:用于@Retryable重试失败后的处理方法。

String Retry有7种重试策略,具体如下:

  • NeverRetryPolicy:只允许调用RetryCallback一次,不允许重试。

  • AlwaysRetryPolicy:允许无限重试,直到成功,此方式逻辑不当会导致死循环。

  • SimpleRetryPolicy:固定次数重试策略,默认重试最大次数为3次,RetryTemplate默认使用的策略。

  • TimeoutRetryPolicy:超时时间重试策略,默认超时时间为1秒,在指定的超时时间内允许重试。

  • ExceptionClassifierRetryPolicy:设置不同异常的重试策略,类似组合重试策略,区别在于这里只区分不同异常的重试。

  • CircuitBreakerRetryPolicy:有熔断功能的重试策略,需设置3个参数openTimeout、resetTimeout和delegate。

  • CompositeRetryPolicy:组合重试策略,有两种组合方式,乐观组合重试策略是指只要有一个策略允许即可以重试,悲观组合重试策略是指只要有一个策略不允许即可以重试,但不管哪种组合方式,组合中的每一个策略都会执行。

String Retry有5种重试回退策略,具体如下:

  • NoBackOffPolicy:无退避算法策略,每次重试时立即重试。

  • FixedBackOffPolicy:固定时间的退避策略,需设置参数sleeper和backOffPeriod,sleeper指定等待策略,默认是Thread.sleep,即线程休眠,backOffPeriod指定休眠时间,默认1秒。

  • UniformRandomBackOffPolicy:随机时间退避策略,需设置sleeper、minBackOffPeriod和maxBackOffPeriod,该策略在minBackOffPeriod、maxBackOffPeriod之间取一个随机休眠时间,minBackOffPeriod默认500毫秒,maxBackOffPeriod默认1500毫秒。

  • ExponentialBackOffPolicy:指数退避策略,需设置参数sleeper、initialInterval、maxInterval和multiplier,initialInterval指定初始休眠时间,默认100毫秒,maxInterval指定最大休眠时间,默认30秒,multiplier指定乘数,即,下一次休眠时间为当前休眠时间multiplier。

  • ExponentialRandomBackOffPolicy:随机指数退避策略,引入随机乘数可以实现随机乘数回退。

二、注解方式使用:

想要使用String Retry,首先要引入架包,然后在启动类上加@EnableRetry注解,最后在需要重试的方法上加@Retryable注解,即可进行重试操作,具体代码如下(注意recover方法上注释,否则有可能不生效):

----- ----- 引入架包 ----- -----
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.1.5.RELEASE</version>
</dependency>

----- ----- 具体代码 ----- -----

   /**
     * 方式2
     * <p>
     * 1. RemoteAccessException的异常才重试
     * 2. @Backoff(delay = 2000L,multiplier = 2)) 表示第一次间隔2秒,以后都是次数的2倍,也就是第二次4秒,第三次6秒
     *
     * @return
     */
    @Retryable(value = {RemoteAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 2))
    public Boolean retry2(String param) {
        return RetryTask.task(param);
    }


    /**
     * recover 机制:达到最大重试次数,或抛出了一个没有指定进行重试的异常,调用此方法
     * <p>
     * Tips:
     * 1. 返回值必须和被重试的函数返回值一致
     * 2. 参数中除了第一个是触发的异常外,后面的参数需要和被重试函数的参数列表一致
     * 3. @Recover注解与@Retryable注解在通过方法中
     *
     * @param e
     * @param param
     * @return
     */
    @Recover
    public Boolean recover(Exception e, String param) {
        log.error("达到最大重试次数,或抛出了一个没有指定进行重试的异常:{},请求参数:{}", e, param);
        return false;
    }

----- ----- 重试任务 ----- -----
public class RetryTask {

    /**
     * 具体任务
     *
     * @param param
     * @return
     */
    public static Boolean task(String param) {

        int num = RandomUtils.nextInt(0, 9);
        log.info("请求参数:[{}],生成随机数:[{}]", param, num);
        if (num == 0) {
            log.info("模拟抛出参数异常");
            throw new IllegalArgumentException("参数异常");
        } else if (num == 1) {
            log.info("模拟执行成功");
            return true;
        } else if (num == 2) {
            log.info("模拟执行失败");
            return false;
        } else {
            log.info("模拟抛出特定异常");
            throw new RemoteAccessException("抛出远程访问异常");
        }
    }

}

三、普通方式使用:

String Retry的普通方式的使用也很简单,具体如下:

    public Boolean retry1() {

        RetryTemplate retryTemplate = new RetryTemplate();

        // 设置重试回退操作策略,主要设置重试间隔时间
        FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
        // 重试间隔时间ms,默认1000ms
        backOffPolicy.setBackOffPeriod(1000L);
        retryTemplate.setBackOffPolicy(backOffPolicy);

        // 设置重试策略,主要设置:重试异常类型、重试次数,默认3次
        Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
        exceptionMap.put(RemoteAccessException.class, true);
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3, exceptionMap);
        retryTemplate.setRetryPolicy(retryPolicy);

        // 执行
        Boolean execute = retryTemplate.execute(
                // 重试回调
                retryCallback -> {
                    boolean result = RetryTask.task("retry1");
                    log.info("调用的结果:{}", result);
                    return result;
                },
                // 在所有尝试都用尽后进行有状态重试的回调
                recoveryCallback -> {
                    log.info("已达到最大重试次数 或 或抛出了不重试的异常 后,进行一些操作");
                    return false;
                }
        );

        log.info("执行结果:{}", execute);

        return execute;
    }

猜你喜欢

转载自blog.csdn.net/huantai3334/article/details/129520640