Spring Retry提供了自动重新调用失败的操作的功能。这在错误可能是暂时性的(例如瞬时网络故障)的情况下很有用。Spring Retry提供对流程和基于策略的行为的声明式控制,易于扩展和自定义。接下来,本文将带大家了解 Spring Retry 的使用方法和部分源码解析
引入spring-retry 相关包
使用spring-retry ,我们只需引入spring-retry 和 aop 的包即可,以 maven 为例:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
使用 spring-retry
@EnableRetry
首先我们需要使用@EnableRetry 注解启用Retry,注册 Retryable 的切点和拦截方法
@Retryable
在我们想要重试的方法上增加@Retryable 注解
@Service
@EnableRetry
public class SpringRetryTest {
@Retryable
public void test() {
System.out.println("test");
throw new RuntimeException();
}
}
这样我们就可以实现一个简单的重试功能了,是不是非常的方便!当然 Spring Retry 支持很多复杂功能的实现,接下来我们就来看一下他的强大功能吧!
@Retryable 参数
-
interceptor
自定义重试拦截器bean名称,用于可重试方法。与其他属性互斥。
//新增自定义拦截器 @Component public class RetryTestInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { //实现具体的拦截策略 System.out.println("retry test interceptor"); return invocation.proceed(); } } //参数为自定义拦截器的 bean 名称 @Retryable(interceptor = "retryTestInterceptor")
-
value
-
include
value 与 include 含义相同,表示可重试的异常类型。默认为空,如果同时exclude 也为空则会重试所有异常。但在使用时需要注意
@Retryable(value = { RuntimeException.class})
-
exclude
不可重试的异常类型。默认为空(如果include也为为空,将重试所有异常)。如果include为空但exclude 不为空,则重试非 exclude 中的异常
@Retryable(exclude = { RuntimeException.class})
-
label
统计报告的唯一标签。如果未提供,则调用者可以选择忽略它或提供默认值。
-
stateful
标记为表示重试是有状态的,默认为 false,在 interceptor 参数中有提到,参数不同使用的拦截器不同,后面我们会讲到不同拦截的作用
-
maxAttempts
最大重试次数,默认是 3
-
maxAttemptsExpression
最大尝试次数的表达式,表达式一旦设置了值,则会覆盖 maxAttempts 的值
//执行 testBean 的 attempts() 方法,获取重试次数 @Retryable(maxAttemptsExpression = "#{@testBean.attempts()}")
-
backoff
用于重试退避策略,比如每隔2s 重试一次,每次重试间隔时间等等,详见@Backoff注解
//第一次延迟 1s 重试,第二次延迟 2s,第三次延迟 4s,... @Retryable(backoff = @Backoff(delay = 1000L, multiplier = 2))
-
exceptionExpression
异常处理表达式,ExpressionRetryPolicy中使用,执行完父类的 canRetry 之后,需要校验 exceptionExpression 的值,为 true 则可以重试
//执行 testBean 的 shouldRetry() 方法,如果为 true,则允许重试 @Retryable(exceptionExpression = "#{@testBean.shouldRetry()}")
-
listeners
重试监听器的 bean 名称。
重试策略
Spring Retry 提供了多种重试策略,比如
-
SimpleRetryPolicy
默认重试策略,简单的重试策略,它对一组命名的异常*(和子类)重试固定次数。尝试次数包括初始尝试
-
AlwaysRetryPolicy
始终允许重试策略,
-
MaxAttemptsRetryPolicy
简单重试策略,仅通过重试次数判断是否能够重试。不建议直接使用它。
-
TimeoutRetryPolicy
超时重试策略,仅在尚未超时的情况下允许重试。
-
NeverRetryPolicy
允许第一次尝试,但不允许重试。
…
还有很多重试策略就不一一介绍了,大家可以自行了解,当然我们也可以通过实现 RetryPolicy 自定义重试策略。
退避策略
退避策略就是我们上面提到的 @Backoff 注解实现的功能,那么我们首先看一下@Backoff 的参数
@Backoff 参数
-
value
默认为 1000, 与 delay 作用相同,表示延迟的毫秒数。当 delay 非 0 时,此参数忽略。
-
delay
默认为 0。在指数情况下用作初始值,在统一情况下用作*的最小值。当此元素的值为0时,将采用元素value的值,否则将采用此元素的值,并且将忽略value。
-
maxDelay
默认为 0。重试之间的最大等待时间(以毫秒为单位)。如果小于delay,那么将应用默认值为30000L
-
multipler
默认为 0。如果为正,则用作乘法器以生成下一个退避延迟。返回一个乘法器,用于计算下一个退避延迟
-
delayExpression
评估标准退避期的表达式。在指数情况下用作初始值*,在均匀情况下用作最小值。覆盖 delay。
-
maxDelayExpression
该表达式计算重试之间的最大等待时间(以毫秒为单位)。 如果小于 delay,那么将应用30000L 为默认值。覆盖 maxDelay。
-
multiplierExpression
评估为用作乘数的值,以生成退避的下一个延迟。覆盖multiplier。 返回一个乘数表达式,用于计算下一个退避延迟
-
random
默认为 false,在指数情况下 multiplier> 0 将此值设置为 true 可以使后退延迟随机化,从而使最大延迟乘以前一延迟,并且两个值之间的分布是均匀的。
@Backoff 的参数会影响我们使用哪种退避策略
-
FixedBackOffPolicy
默认退避策略,每 1 秒重试 1 次
-
ExponentialBackOffPolicy
指数退避策略,当设置 multiplier 时使用,每次重试时间间隔为 当前延迟