SpringRetry 调用方法出现异常后进行重试。
场景:后端进行远程调用,可能会出现网络波动而导致远程调用失败,需要在调用失败后进行重试,重试间隔为2秒,重试次数为3次。通过spring retry就能够完美的实现
1 引入依赖
<!-- retry底层通过aop实现,必须引入aop依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- spring retry依赖 -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2. 代码
1 通过 @EnableRetry 开启retry功能
@EnableRetry
@SpringBootApplication
public class WebTestApplication {
public static void main(String[] args) {
SpringApplication.run(WebTestApplication.class, args);
}
}
2 在对应的方法上新增@Retryable注解
@Slf4j
@Service
public class TestService {
/**
@Retryable在进行重试的时候是同步的(controller只有在重试3次后才返回结果)
如果需要支持异步,需要配合@Asyc实现
*/
@Async
@Retryable(value = {Throwable.class},maxAttempts = 3,backoff = @Backoff(value = 2000,multiplier = 2))
public void retryMethod(Integer param) {
int i = new Random().nextInt(param);
log.info("随机生成的数:{}", i);
if (1 == i) {
log.info("为1,返回true.");
} else if (i > 5) {
log.info("大于5,抛出参数异常.");
throw new IllegalArgumentException("大于5,抛出参数异常."+i);
} else if ( i> 10) {
log.info("大于10,直接返回false");
} else {
//为其他
log.info("小于5,抛出自定义异常.");
throw new RemoteAccessException("小于5,抛出自定义异常."+i);
}
}
/**
加了@Recover的方法会兜底方法,在重试失败后会进行调用
一个类内可以有多个@Recover方法,选取时根据异常进行匹配,和@ExceptionHandler类似
*/
@Recover
public void recover1(Throwable e){
log.error("重试方法出现异常--->{}",e.getMessage());
}
}
3 @RetryAble 常用参数
public @interface Retryable {
/**
* 一般不用
*/
String recover() default "";
/**
* 一般不用
*/
String interceptor() default "";
/**
* 当跑出对应异常时进行重试
*/
Class<? extends Throwable>[] value() default {};
/**
* 和value一样
*/
Class<? extends Throwable>[] include() default {};
/**
* 忽略某些异常
*/
Class<? extends Throwable>[] exclude() default {};
/**
* 一般不用
*/
String label() default "";
/**
* 一般不用
*/
boolean stateful() default false;
/**
* 重试次数,默认为3
*/
int maxAttempts() default 3;
/**
* 返回重试次数的表达式,一般不用
*/
String maxAttemptsExpression() default "";
/**
* 配置重试的细节,如重试间隔时间等
*/
Backoff backoff() default @Backoff();
/**
*
*/
String exceptionExpression() default "";
/**
*
*/
String[] listeners() default {};
}
Backoff
public @interface Backoff {
// 与delay效果等价,失败后等待多少ms重试下一次
long value() default 1000;
// 与valuey效果等价,失败后等待多少ms重试下一次
long delay() default 0;
// 重试等待的最大时间与delay配合使用,以下是一些结论
// 1. 如果@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000,maxDelay = 9000)) 则本例等待时间是1000~9000之间随机
// 2. 如果配合multiplier使用时,maxDelay<delay,@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 1000,maxDelay = 900,multiplier=1.5)),则本例子等待时间是1000~30000之间,也就是在multiplier配置的情况下,maxDelay非0,且maxDelay<delay,则maxDelay=30s
long maxDelay() default 0;
// 可以指数增长重试间隔
double multiplier() default 0;
String delayExpression() default "";
String maxDelayExpression() default "";
String multiplierExpression() default "";
// 在使用multiplier时有效,配置为true,每次延迟的时间会有一定的随机
boolean random() default false;
}