楔子
在应用程序中,由于一些网络等不可预知的问题,我们的程序或者接口会失败,比如调用一个第三方的接口获取数据失败了,这时就需要重试机制,比如延时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时,方法一共只执行了一次。