Spring Retry是Spring提供的重试机制,它支持注解方式进行配置,可以做到代码无浸入的重试操作。它的使用也很简单,我们先了解一下Spring Retry的基础概念。
一、基础概念:
String Retry支持普通方式使用和注解方式使用(下文中会展示写法)。我们重点说一下注解方式使用,这里主要设计到三个注解,具体如下:
@EnableRetry :添加在启动类上,表示开启重试。
@Retryable:添加在需要重试的方法上,该方法在发生异常时,会进行重试。
@Recover:用于@Retryable重试失败后的处理方法。
String Retry有7种重试策略,具体如下:
NeverRetryPolicy:只允许调用RetryCallback一次,不允许重试。
AlwaysRetryPolicy:允许无限重试,直到成功,此方式逻辑不当会导致死循环。
SimpleRetryPolicy:固定次数重试策略,默认重试最大次数为3次,RetryTemplate默认使用的策略。
TimeoutRetryPolicy:超时时间重试策略,默认超时时间为1秒,在指定的超时时间内允许重试。
ExceptionClassifierRetryPolicy:设置不同异常的重试策略,类似组合重试策略,区别在于这里只区分不同异常的重试。
CircuitBreakerRetryPolicy:有熔断功能的重试策略,需设置3个参数openTimeout、resetTimeout和delegate。
CompositeRetryPolicy:组合重试策略,有两种组合方式,乐观组合重试策略是指只要有一个策略允许即可以重试,悲观组合重试策略是指只要有一个策略不允许即可以重试,但不管哪种组合方式,组合中的每一个策略都会执行。
String Retry有5种重试回退策略,具体如下:
NoBackOffPolicy:无退避算法策略,每次重试时立即重试。
FixedBackOffPolicy:固定时间的退避策略,需设置参数sleeper和backOffPeriod,sleeper指定等待策略,默认是Thread.sleep,即线程休眠,backOffPeriod指定休眠时间,默认1秒。
UniformRandomBackOffPolicy:随机时间退避策略,需设置sleeper、minBackOffPeriod和maxBackOffPeriod,该策略在minBackOffPeriod、maxBackOffPeriod之间取一个随机休眠时间,minBackOffPeriod默认500毫秒,maxBackOffPeriod默认1500毫秒。
ExponentialBackOffPolicy:指数退避策略,需设置参数sleeper、initialInterval、maxInterval和multiplier,initialInterval指定初始休眠时间,默认100毫秒,maxInterval指定最大休眠时间,默认30秒,multiplier指定乘数,即,下一次休眠时间为当前休眠时间multiplier。
ExponentialRandomBackOffPolicy:随机指数退避策略,引入随机乘数可以实现随机乘数回退。
二、注解方式使用:
想要使用String Retry,首先要引入架包,然后在启动类上加@EnableRetry注解,最后在需要重试的方法上加@Retryable注解,即可进行重试操作,具体代码如下(注意recover方法上注释,否则有可能不生效):
----- ----- 引入架包 ----- -----
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.1.5.RELEASE</version>
</dependency>
----- ----- 具体代码 ----- -----
/**
* 方式2
* <p>
* 1. RemoteAccessException的异常才重试
* 2. @Backoff(delay = 2000L,multiplier = 2)) 表示第一次间隔2秒,以后都是次数的2倍,也就是第二次4秒,第三次6秒
*
* @return
*/
@Retryable(value = {RemoteAccessException.class}, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 2))
public Boolean retry2(String param) {
return RetryTask.task(param);
}
/**
* recover 机制:达到最大重试次数,或抛出了一个没有指定进行重试的异常,调用此方法
* <p>
* Tips:
* 1. 返回值必须和被重试的函数返回值一致
* 2. 参数中除了第一个是触发的异常外,后面的参数需要和被重试函数的参数列表一致
* 3. @Recover注解与@Retryable注解在通过方法中
*
* @param e
* @param param
* @return
*/
@Recover
public Boolean recover(Exception e, String param) {
log.error("达到最大重试次数,或抛出了一个没有指定进行重试的异常:{},请求参数:{}", e, param);
return false;
}
----- ----- 重试任务 ----- -----
public class RetryTask {
/**
* 具体任务
*
* @param param
* @return
*/
public static Boolean task(String param) {
int num = RandomUtils.nextInt(0, 9);
log.info("请求参数:[{}],生成随机数:[{}]", param, num);
if (num == 0) {
log.info("模拟抛出参数异常");
throw new IllegalArgumentException("参数异常");
} else if (num == 1) {
log.info("模拟执行成功");
return true;
} else if (num == 2) {
log.info("模拟执行失败");
return false;
} else {
log.info("模拟抛出特定异常");
throw new RemoteAccessException("抛出远程访问异常");
}
}
}
三、普通方式使用:
String Retry的普通方式的使用也很简单,具体如下:
public Boolean retry1() {
RetryTemplate retryTemplate = new RetryTemplate();
// 设置重试回退操作策略,主要设置重试间隔时间
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
// 重试间隔时间ms,默认1000ms
backOffPolicy.setBackOffPeriod(1000L);
retryTemplate.setBackOffPolicy(backOffPolicy);
// 设置重试策略,主要设置:重试异常类型、重试次数,默认3次
Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
exceptionMap.put(RemoteAccessException.class, true);
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3, exceptionMap);
retryTemplate.setRetryPolicy(retryPolicy);
// 执行
Boolean execute = retryTemplate.execute(
// 重试回调
retryCallback -> {
boolean result = RetryTask.task("retry1");
log.info("调用的结果:{}", result);
return result;
},
// 在所有尝试都用尽后进行有状态重试的回调
recoveryCallback -> {
log.info("已达到最大重试次数 或 或抛出了不重试的异常 后,进行一些操作");
return false;
}
);
log.info("执行结果:{}", execute);
return execute;
}