Spring-retry详解( 五 )

主要核心重试逻辑就是上面的代码了 , 看上去还是挺简单的 。下面看 RetryPolicy 的 canRetry 方法和 BackOffPolicy 的 backOff 方法 , 以及这两个 Policy 是怎么来的 。我们回头看看getStatelessInterceptor方法中的getRetryPolicy和getRetryPolicy方法 。
private RetryPolicy getRetryPolicy(Annotation retryable) {Map<String, Object> attrs = AnnotationUtils.getAnnotationAttributes(retryable);@SuppressWarnings("unchecked")Class<? extends Throwable>[] includes = (Class<? extends Throwable>[]) attrs.get("value");//通过注解属性判断重试策略 这里判断如果 value 注解内容为空才去获取 include 注解的内容 可得出 value 的优先级大于 includeString exceptionExpression = (String) attrs.get("exceptionExpression");boolean hasExpression = StringUtils.hasText(exceptionExpression);if (includes.length == 0) {@SuppressWarnings("unchecked")Class<? extends Throwable>[] value = https://www.isolves.com/it/cxkf/kj/2023-05-18/(Class[]) attrs.get("include");includes = value;}@SuppressWarnings("unchecked")Class[] excludes = (Class[]) attrs.get("exclude");Integer maxAttempts = (Integer) attrs.get("maxAttempts");String maxAttemptsExpression = (String) attrs.get("maxAttemptsExpression");if (StringUtils.hasText(maxAttemptsExpression)) {maxAttempts = PARSER.parseExpression(resolve(maxAttemptsExpression), PARSER_CONTEXT).getValue(this.evaluationContext, Integer.class);}if (includes.length == 0 && excludes.length == 0) {SimpleRetryPolicy simple = hasExpression ? new ExpressionRetryPolicy(resolve(exceptionExpression)).withBeanFactory(this.beanFactory): new SimpleRetryPolicy();simple.setMaxAttempts(maxAttempts);return simple;}Map, Boolean> policyMap = new HashMap, Boolean>();for (Class type : includes) {policyMap.put(type, true);}for (Class type : excludes) {policyMap.put(type, false);}boolean retryNotExcluded = includes.length == 0;if (hasExpression) {return new ExpressionRetryPolicy(maxAttempts, policyMap, true, exceptionExpression, retryNotExcluded).withBeanFactory(this.beanFactory);}else {return new SimpleRetryPolicy(maxAttempts, policyMap, true, retryNotExcluded);} }总结一下:就是通过 @Retryable 注解中的参数 , 来判断具体使用文章开头说到的哪个重试策略 , 是 SimpleRetryPolicy 还是 ExpressionRetryPolicy 等 。
private BackOffPolicy getBackoffPolicy(Backoff backoff) {long min = backoff.delay() == 0 ? backoff.value() : backoff.delay();if (StringUtils.hasText(backoff.delayExpression())) {min = PARSER.parseExpression(resolve(backoff.delayExpression()), PARSER_CONTEXT).getValue(this.evaluationContext, Long.class);}long max = backoff.maxDelay();if (StringUtils.hasText(backoff.maxDelayExpression())) {max = PARSER.parseExpression(resolve(backoff.maxDelayExpression()), PARSER_CONTEXT).getValue(this.evaluationContext, Long.class);}double multiplier = backoff.multiplier();if (StringUtils.hasText(backoff.multiplierExpression())) {multiplier = PARSER.parseExpression(resolve(backoff.multiplierExpression()), PARSER_CONTEXT).getValue(this.evaluationContext, Double.class);}if (multiplier > 0) {ExponentialBackOffPolicy policy = new ExponentialBackOffPolicy();if (backoff.random()) {policy = new ExponentialRandomBackOffPolicy();}policy.setInitialInterval(min);policy.setMultiplier(multiplier);policy.setMaxInterval(max > min ? max : ExponentialBackOffPolicy.DEFAULT_MAX_INTERVAL);if (this.sleeper != null) {policy.setSleeper(this.sleeper);}return policy;}if (max > min) {UniformRandomBackOffPolicy policy = new UniformRandomBackOffPolicy();policy.setMinBackOffPeriod(min);policy.setMaxBackOffPeriod(max);if (this.sleeper != null) {policy.setSleeper(this.sleeper);}return policy;}FixedBackOffPolicy policy = new FixedBackOffPolicy();policy.setBackOffPeriod(min);if (this.sleeper != null) {policy.setSleeper(this.sleeper);}return policy; }就是通过 @Backoff 注解中的参数 , 来判断具体使用文章开头说到的哪个退避策略 , 是 FixedBackOffPolicy 还是 UniformRandomBackOffPolicy 等 。
那么每个 RetryPolicy 都会重写 canRetry 方法 , 然后在 RetryTemplate 判断是否需要重试 。我们看看 SimpleRetryPolicy 的
@Override public boolean canRetry(RetryContext context) {Throwable t = context.getLastThrowable();//判断抛出的异常是否符合重试的异常//还有 , 是否超过了重试的次数return (t == null || retryForException(t)) && context.getRetryCount() < maxAttempts; }同样 , 我们看看 FixedBackOffPolicy 的退避方法 。
protected void doBackOff() throws BackOffInterruptedException {try {//就是 sleep 固定的时间sleeper.sleep(backOffPeriod);}catch (InterruptedException e) {throw new BackOffInterruptedException("Thread interrupted while sleeping", e);} }


推荐阅读