WHAT
@Retryable由spring-retry模块提供,在方法或类上添加@Retryable注解可以实现方法调用失败的重试。可以指定失败重试的次数、fallback方法
@Retryable
设置重试的次数、指定需要重试的异常
1 | @Target({ ElementType.METHOD, ElementType.TYPE }) |
@Backoff
设置重试的时间间隔,不同值的组合会确定不同的计算间隔方式
1 | @Target(ElementType.TYPE) |
@Recover
重试失败后会进入@Recover注解的方法
WHY
在项目中假设调用的外部服务发生网络异常、服务器故障、死机状况,在这些情况下通常会重试几次调用,假如最终还是失败则会返回特定的内容。如果可能在后续的尝试中会成功,则有重试的必要。你可能会写一段循环代码然后计数来实现重试功能,@Retryable提供了更便捷的方式来实现错误重试
1 | BEFORE: |
HOW
@Retryable如何使用?怎么实现的?
- Requirements
1
2
3
4
5
6
7
8
9
10<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${version}</version>
</dependency>
事例
1 | public interface RetryService { |
原理
AOP
- RetryConfiguration 创建pointcut(Retryable注解), 创建Advice(AnnotationAwareRetryOperationsInterceptor)
- AnnotationAwareRetryOperationsInterceptor 委托给默认的 RetryOperationsInterceptor
BackOffPolicy
@Backoff
- multiplier > 0 and random = false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16initialInterval = delay
maxInterval = maxDelay > initialInterval ? maxDelay : ExponentialBackOffPolicy.DEFAULT_MAX_INTERVAL(30000毫秒)
public synchronized long getSleepAndIncrement() {
long sleep = this.interval;
if (sleep > maxInterval) {
sleep = maxInterval;
}
else {
this.interval = getNextInterval();
}
return sleep;
}
protected long getNextInterval() {
return (long) (this.interval * this.multiplier);
} - multiplier > 0 and random = true
1
2
3
4
5
6public synchronized long getSleepAndIncrement() {
// 1 中方法
long next = super.getSleepAndIncrement();
next = (long) (next * (1 + r.nextFloat() * (getMultiplier() - 1)));
return next;
} - maxDelay > initialInterval
1
2long delta = maxDelay==initialInterval ? 0 : random.nextInt((int) (maxDelay - minBackOffPeriod));
sleeper.sleep(minBackOffPeriod + delta ); - 其他
1
sleeper.sleep(delay);
注意点
- @Recover只对同类中的@Retryable生效
- 多个@Recover方法,同一种异常参数。相当于讲这些方法(Method)放在Set中,取出的第一个@Recover方法将会是fallback方法
- 多个@Recover方法,不同种异常参数。若@Recover方法参数距离@Retryable方法抛出的异常最近(根据重试的最后一次抛出的异常作为查找依据)则此@Recover方法将会是fallback方法。
1
RecoverAnnotationRecoveryHandler.findClosestMatch
If you find that one thing that keeps you going, you’ve got to hold onto it. - Red