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注解说明:用于兜底,当 超出了最大重试次数 或 抛出了不进行重试的异常 时,直接执行该注解声明的兜底方法。
原理分析
- @EnableRetry 注解引入了 RetryConfiguration 配置类。
- 创建 AnnotationAwareRetryOperationsInterceptor 拦截器,扫描类或方法上的 @Retryable 注解。
- 如果有扫描到,创建 RetryOperationsInterceptor 拦截器,内部交给 RetryTemplate 来执行重试
总结
Spring-Retry 使用是很方便的,但是如果重试策略设置错误,也是有很大的风险的(比如无限重试)。