写在前面
Spring Retry为Spring提供的重试模块,spring retry是从spring batch独立出来的一个能功能,主要实现了重试和熔断。对于重试是有场景限制的,不是什么场景都适合重试,比如参数校验不合法、写操作等(要考虑写是否幂等)都不适合重试。远程调用超时、网络突然中断可以重试。在微服务治理框架中,通常都有自己的重试与超时配置,比如dubbo可以设置retries=1,timeout=500调用失败只重试1次,超过500ms调用仍未返回则调用失败。在spring retry中可以指定需要重试的异常类型,并设置每次重试的间隔以及如果重试失败是继续重试还是熔断(停止重试)。目前提供了注解方式使用,包括@EnableRetry,@Retryable,@Backoff等注解。
使用
在启动类中使用@EnableRetry注解。
@SpringBootApplication
@EnableRetry
public class SpringDemoRetryApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDemoRetryApplication.class, args);
}
}
在需要重试机制中加入重试注解,包括熔断和重试模式。
@Service
@Slf4j
public class HelloServiceImpl implements HelloService {
@Override
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000L, multiplier = 1.5))
public String hello(String username) {
log.debug("hello,{}",username);
int random=(int)(Math.random()*30);
if(random%4!=0){
throw new RuntimeException("error");
}
return "hello world,"+username;
}
}
测试结果如下,重试三次失败,采用最快失败。
6699 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
6832 [main] DEBUG c.m.s.d.r.s.impl.HelloServiceImpl - hello,luzhu
6833 [main] DEBUG o.s.r.b.ExponentialBackOffPolicy - Sleeping for 2000
8833 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
8833 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=1
8833 [main] DEBUG c.m.s.d.r.s.impl.HelloServiceImpl - hello,luzhu
8834 [main] DEBUG o.s.r.b.ExponentialBackOffPolicy - Sleeping for 3000
11834 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=2
11835 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=2
11835 [main] DEBUG c.m.s.d.r.s.impl.HelloServiceImpl - hello,luzhu
11835 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=3
11836 [main] DEBUG o.s.retry.support.RetryTemplate - Retry failed last attempt: count=3
源码分析
重试模块主要由spring-retry模块实现,代码组织如下:
- 重试接口(RetryOperations)
RetryOperations类主要实现了对重试的接口,RetryTemplate为其实现。主要包括execute方法,RetryCallback为重试需要执行的操作,RecoverCallback为重试结束后如何返回,比如提供默认值等等,即重试失败后需要进行的操作。重试包括如何重试,RetryTemplate默认的重试策略为SimpleRetryPlicy。
- 重试上下文(RetryContext)
重试上下文接口为RetryContext,其中继承了AttributeAccessor接口,此接口提供了对扩展属性的增删查改操作,用于对不同重试情况下特性的支持,RetryContext实现由AttributeAccessorSupport类实现(map集合实现)。RetryContextSupport类提供了一些重试基础数据的记录,包括重试次数,重试上文,最新异常,是否结束等。默认实现为SimpleRetryContext。- SimpleRetryContext:默认实现;
- NeverRetryContext:新增是否结束字段;
- TimeoutRetryContext:扩展开始时间和过期时间字段,判断是否过期;
- 重试策略(RetryPolicy)
重试策略接口为RetryPolicy,其中包括是否能够重试canRetry,打开重试上下文 open,关闭重试上下文close,注册异常信息registerThorwable四个类。具体策略中open将打开对应的上下文,比如NeverRetryPolicy打开NeverRetryContext,而具体是否继续重试由canRetry控制,比如NeverRetry会去判断context是否结束(!((NeverRetryContext) context).isFinished();),AlwaysRetryPolicy策略一直返回true;SimpleRetryPolicy会去