需求
在应用程序中,由于一些网络等不可预知的问题,我们的程序或者接口会失败,比如调用一个第三方的接口获取数据失败了,这时就需要重试机制,比如延时 3S 后重试、间隔不断增加重试等,而这些机制完全不需要你自己去实现,全部交给 Spring Retry 吧。
使用
1. 在 pom 文件中添加相应的依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
最新版本可以在 Maven Central 找到 Spring Retry 使用 AOP 实现,所以必须要有 spring-aspects 依赖,
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
2. 在启动类或者配置类上添加注解 @EnableRetry
配置类
@Configuration
@EnableRetry
public class AppConfig { ... }
启动类
@SpringBootApplication
@EnableRetry
public class Application
3. 在需要重试的方法上添加注解 @Retryable
@Service
public class DemoService {
@Retryable(value= {Exception.class},maxAttempts = 3)
public void call() throws Exception {
System.out.println("do something...");
throw new Exception("RPC调用异常");
}
@Recover
public void recover(RemoteAccessException e) {
System.out.println(e.getMessage());
}
}
@Retryable(maxAttempts = 3, backoff = @Backoff(value = 3000, multiplier = 1.5))
public Customer getCustomer(String customerId) {
if (true) {
JSONArray data = retObj.getJSONArray("data");
if (data != null && !data.isEmpty()) {
return data.toJavaList(Customer.class).get(0);
}
} else {
log.error("异常,{}", customerId);
throw new RuntimeException("获数据失败");
}
return null;
}
@Retryable
被注解的方法发生异常时会重试
“”
@Retryable
注解中的参数说明:maxAttempts : 最大重试次数,默认为 3,如果要设置的重试次数为 3,可以不写;value:抛出指定异常才会重试 include:和 value 一样,默认为空,当 exclude 也为空时,所有异常都重试 exclude:指定不处理的异常,默认空,当 include 也为空时,所有异常都重试 backoff:重试等待策略,默认使用 @Backoff@Backoff 的 value 默认为 1000L,我们设置为 2000L。
@Backoff
重试补偿机制,默认没有
“”
@Backoff
注解中的参数说明:value:隔多少毫秒后重试,默认为 1000L,我们设置为 3000L;delay:和 value 一样,但是默认为 0;multiplier(指定延迟倍数)默认为 0,表示固定暂停 1 秒后进行重试,如果把 multiplier 设置为 1.5,则第一次重试为 2 秒,第二次为 3 秒,第三次为 4.5 秒。
4. 可以在指定方法上标记 @Recover 来开启重试失败后调用的方法 (注意, 需跟重处理方法在同一个类中)
@Recover
:当重试到达指定次数时,被注解的方法将被回调,可以在该方法中进行日志处理。需要注意的是发生的异常和入参类型一致时才会回调。
5. 采坑提示
1、由于 retry 用到了 aspect 增强,所有会有 aspect 的坑,就是方法内部调用,会使 aspect 增强失效,那么 retry 当然也会失效。参考改链接
public class demo {
public void A() {
B();
}
//这里B不会执行
@Retryable(Exception.class)
public void B() {
throw new RuntimeException("retry...");
}
}
2、重试机制,不能在接口实现类里面写。所以要做重试,必须单独写个 service。
3、maxAttemps 参数解释的是说重试次数,但是我再打断点的时候发现这个 = 1 时,方法一共只执行了一次。
参考文献
@Retryable(spring 的重试机制) https://juejin.im/post/5d97630ef265da5bad405134
@Retryable(spring 的重试机制) https://blog.csdn.net/qq_20989105/article/details/80003087
https://www.baeldung.com/spring-retry
作者:jieniyimiao
来源链接:
https://blog.csdn.net/u013467442/article/details/105746620