不知道有没有小伙伴因为调用服务中的种种问题,如:调用异常、结果未返回、网络抖动等等,需要进行重试而困扰过。java的重试机制有很多种,今天咱们一起学习一下Spring-Retry。
什么是Spring Retry
Spring Retry为Spring应用程序提供声明式重试支持,我们可以使用@Retryable和@Recover,快捷的实现重试和补偿策略。
Spring Retry GitHub地址
https://github.com/spring-projects/spring-retry
Spring Retry 实例
1、添加pom依赖
<!-- retry重试 依赖 -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
2、SpringbootMysqlMybatisDemoApplication 启动类加上@EnableRetry注解
package com.example.demo.smm;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
@SpringBootApplication
@EnableRetry
public class SpringbootMysqlMybatisDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMysqlMybatisDemoApplication.class, args);
}
}
3、在需要的方法上加上@Retryable 和 @Recover注解
//最大重试3次,每次重试延迟2s->3s->4.5s
@Retryable(include = RuntimeException.class, maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
@Override
public UserInfo getHttpReTryTest(Integer num) throws Exception {
num ++;
if(num > 1) {
System.out.println("运行getHttpReTryTest方法--------------------");
throw new RuntimeException("强制抛出异常,getUserInfoByIdReTryTest num:" + num);
} else {
System.out.println("运行getHttpReTryTest方法********************");
throw new IOException("强制抛出异常,getUserInfoByIdReTryTest num:" + num);
}
}
//最大重试3次,每次重试延迟2s->3s->4.5s
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 20000,maxDelay = 80000, multiplier = 2))
@Override
public Long insertHttpReTryTest(UserInfo userInfo) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd : HH:mm:ss");
System.out.println("调用http方法:" + simpleDateFormat.format(new Date()));
throw new RuntimeException("强制抛出异常,insertHttpReTryTest result:" + userInfo.toString());
}
@Recover
public UserInfo getHttpReTryTestRuntimeException(RuntimeException e) {
System.out.println("调用getHttpReTryTestRuntimeException方法 e:" + e.getMessage());
return new UserInfo();
}
@Recover
public UserInfo getHttpReTryTestIOException(IOException e) {
System.out.println("getHttpReTryTestIOException e:" + e.getMessage());
return new UserInfo();
}
@Recover
public Long insertHttpReTryTestException(RuntimeException e) {
System.out.println("调用insertHttpReTryTestException方法 e:" + e.getMessage());
return 0L;
}
Spring Retry 注解属性详解
1、@EnableRetry 作用于SpringbootApplication启动类,开启spring retry。
proxyTargetClass:默认值为false,设置为true时为CGLIB代理。
2、@Retryable 作用于需要进行重试的方法
value:指定处理的异常类,默认为空
include:指定处理的异常类,默认为空,当include和exclude为空时,默认所有异常
exclude:指定哪些异常不处理,默认空
maxAttempts:最大重试次数。默认3次
backoff: 重试补偿策略。默认使用@Backoff注解
3、@Backoff 作用于backoff中的补偿策略
delay:指定等待时间,没有设置的话默认为1000ms
maxDelay:最大重试时间,没有设置默认为3000ms
multiplier:下一次调用时间的乘数
random:随机等待时间,默认值为false
4、@Recover 用于对retry方法的异常抛出的特殊处理,可做熔断、降级、日志等操作。入参必须和retry对应方法所抛出的异常类型相同。
注意点
1、因为maxDelay的默认值为30000ms,没有设置时,要注意自己的最大重试时间是否会超过30000ms,如下:
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 20000, multiplier = 2))
把maxDelay设置为80000ms后,第三次调用间隔为预期的40000ms
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 20000,maxDelay = 80000, multiplier = 2))
2、如果需要随机重试值,开启random,效果如下:
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(maxDelay = 80000, multiplier = 2,random = true))
3、本质上retry是使用的aop切面,所以要注意aop的一些问题,在retry也会出现,如内嵌调用失效等。
4、重试时要注意接收者是否有做幂等操作,支持重试。
以上为Spring Retry的使用内容,使用Retry可以让我们快捷方便的实现各种重试方式。