使用Spring Retry组件优雅地实现重试
一.引入依赖
1.retry依赖
<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId><version>1.2.5.RELEASE</version></dependency>
2.AspectJ依赖
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version></dependency>
retry组件需要用到aop的功能,所以需要引入第二个功能依赖
二.基于注解实现开发
1.首先需要在启动类上加注解@EnableRetry
2.要重试的方法上加@Retryable注解
@Retryable(include = {IOException.class}, maxAttempts = 4, backoff = @Backoff(delay = 2000L, multiplier = 2))
include:可以定义允许重试的异常情况
maxAttemp:重试的次数,需要减去一,如果该参数为4,实际重试3次,另一个是第一次请求。
backoff:定义重试策略,delay表示第一次重试间隔的时间,上面为2秒,multiplier = 2表示后面每次重试的间隔时间是之前的2倍。例如第一次重试需间隔2秒,第二次重试则间隔4秒,第三次重试则间隔8秒。
三.注意的事项
1.重试失效
如果一个类中存在两个方法,A,B。他们的调用关系如下,则B中的重试会失效。
public String A() {B("aaaa");return "";
}@Retryable(include = {IOException.class}, maxAttempts = 4, backoff = @Backoff(delay = 2000L, multiplier = 1))
public Strinf B(String input){}
因为重试的时候走的是代理,上面调用代理失效了。然后我做了下面的尝试,本以为这样可以成功,但还是没有重试。(读者可自行尝试)
public class AServiceImpl {@Autowiredprivate IFsopSignApproveService this;public String A() {this.B("aaa");return "";}@Retryable(include = {IOException.class}, maxAttempts = 4, backoff = @Backoff(delay = 2000L, multiplier = 1))public Strinf B(String input) {}}
所以,最好在需要重试的方法上加重试,也不要存在调用关系。
2.RetryTemplate类使用
或者我们可以使用RetryTemplate类进行开发,代码中手动控制重试逻辑。a代码中实现逻辑如下。
// 创建 RetryTemplate 实例
RetryTemplate retryTemplate = new RetryTemplate();// 配置重试策略 - 设置最大重试次数(包含首次调用)
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(4); // 最多尝试4次// 配置退避策略 - 固定间隔重试
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(2000); // 重试间隔2秒// 设置策略
retryTemplate.setRetryPolicy(retryPolicy);
retryTemplate.setBackOffPolicy(backOffPolicy);retryTemplate.execute(context -> {// 调用可能会失败的方法AServiceImpl.B("aaaaaa");return null;
});
另外,include里面可以进行拓展异常,把代码运行可能出现的异常情况进行定义,抛出异常,在include属性里面添加,该方法便会重试。
3.@Recover方法的补充机制
如果重试完了都失败了,还可以做最后的兜底,与 @Retryable 方法在同一个类中使用@Recover注解写一个方法,@Recover方法的第一个参数必须是触发重试的异常类型,随后的参数应与@Retryable方法的参数列表一致,且具有兼容的返回类型和参数列表。最后没有重试成功便会走这个方法。
@Recoverpublic String recover(IOException e,String input){ return "补偿机制:"+input;}
四.总结
Spring Retry组件是一个小型的框架,使用注解开发非常方便我们去使用在需要业务重试的地方。而且功能也比较丰富,可以做进一步探索,使用RetryTemplate类可以配置重试的一些策略。
并且我们可以进一步研究他的日志策略,方便我们知道重试的情况。