Spring-Retry框架简单使用

前言

Spring-Retry 框架是 Spring 自带的功能,具备间隔重试、包含异常、排除异常、控制重试频率等特点,是项目开发中很实用的一种框架。SpringCloudConfig请求配置中心服务器时就使用到了此功能,具体可以看 ConfigServicePropertySourceLocator。

使用

添加依赖

底层使用 AOP 实现的,所以也需要添加 AOP 的依赖

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

开启配置

使用 @EnableRetry 注解

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

模拟发短信

@Slf4j
@Component
public class RetryService {

    /**
     * 重试机制发送短信
     */
    @Retryable(
            include = {IllegalArgumentException.class, ArrayIndexOutOfBoundsException.class},
            exclude = {NullPointerException.class},
            maxAttempts = 4,
            backoff = @Backoff(delay = 2000L, multiplier = 2)
    )
    public boolean sendSmsRetry() {
        log.info("[RetryComponent][sendSmsRetry]>>>> 当前时间:{}", getNowTime());
        return 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"));
    }

    /**
     * 模拟发送短信
     */
    private boolean sendSms() {
        int num = RandomUtils.nextInt(0, 5);
        log.info("[SmsUtil][sendSms]>>>> random num = {}", num);
        switch (num) {
            case 0:
                // 模拟发生参数异常
                throw new IllegalArgumentException("参数有误!");
            case 1:
                // 模拟发生数组越界异常
                throw new ArrayIndexOutOfBoundsException("数组越界!");
            case 2:
                // 模拟成功
                return true;
            case 3:
                // 模拟发生空指针界异常
                throw new NullPointerException();
            default:
                // 未成功则返回false
                return false;
        }
    }
}
@Slf4j
@RestController
public class TestRetryController {

    @Autowired
    private RetryService retryService;

    @GetMapping("/testRetry")
    public boolean testRetry() {
        boolean ret = retryService.sendSmsRetry();
        log.info("sendSmsRetry result = {}", ret);
        return ret;
    }
}

@Retryable 注解参数说明:

  • include:要触发重试的异常列表,如果 include 为空且 exclude 也为空,表示所有异常都触发(Exception类)。
  • exclude:不要触发重试的异常列表。
  • maxAttempts:重试最大次数,默认3次。
  • backoff:定义补偿机制,delay-延迟时间(s),multiplier-重试时间的倍数(比如设置为2,重试4次的话,补偿机制就是分别间隔2s、4s、8s做重试),默认延迟1s

@Recover注解说明:用于兜底,当 超出了最大重试次数 或 抛出了不进行重试的异常 时,直接执行该注解声明的兜底方法。

原理分析

  1. @EnableRetry 注解引入了 RetryConfiguration 配置类。
  2. 创建 AnnotationAwareRetryOperationsInterceptor 拦截器,扫描类或方法上的 @Retryable 注解。
  3. 如果有扫描到,创建 RetryOperationsInterceptor 拦截器,内部交给 RetryTemplate 来执行重试

总结

Spring-Retry 使用是很方便的,但是如果重试策略设置错误,也是有很大的风险的(比如无限重试)。

参考

5分钟攻略Spring-Retry框架实现经典重试场景

posted @ 2024-04-21 14:34  strongmore  阅读(126)  评论(0编辑  收藏  举报