重试框架spring-retry的探索与揭秘

1、前言

     在项目中,我们经常会遇到网络波动,或者调用第三方接口偶尔异常的情况。为了保证数据的可用性、程序的健壮性。我们常常加入重试的操作,多请求几次,若干次请求之后,如果还是失败,才算是真正的失败。成熟的框架上都有体现,比如dubbo的重试机制,spring全家桶自带的重试、以及google出品的guava里的重试机制等。今天以Spring框架中的重试机制为例分析、学习。

2、接入依赖

这里的依赖引用的是目前最新的版本,和老版本里的使用稍微有点差异,后面会详细说明。

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.3.1</version>
</dependency>

3、初体验

@Test
public void retry01(){
	RetryTemplate retryTemplate = RetryTemplate.builder().maxAttempts(3).fixedBackoff(2000).build();
	retryTemplate.execute(new RetryCallback(){
		@Override
		public Object doWithRetry(RetryContext context) throws Throwable {
			System.out.println(">>>>>>>>>>>>>>>>>retry test"+ DateUtils.formatDate(new Date()));
			throw new RuntimeException("retry excption");
		}
	}, new RecoveryCallback(){
		@Override
		public Object recover(RetryContext context) throws Exception {
			System.out.println(">>>>>>>>>>>>>>>>>retry test fail");
			return null;
		}
	});
	System.out.println("over");
}

4、结果

5、详细分析

     上述demo中,实现了每隔2s,重试一次,重试三次后再执行后处理(“retry test fail”),最终结束程序的运行。

RetryTemplate:通过重试模板构建一个指定的模板,通过设置请求的次数(maxAttempts),设置时间间 隔(fixedBackoff).

    通过excute方法,并传入参数执行方法。

RetryCallback:重试回调接口。指重复请求的业务逻辑需要实现RetryCallback.doWithRetry()方法。

RetryContext: 执行重试过程的上下文。
RecoveryCallback:重试结束依然没有想要的结果,需要处理的业务接口。同样需要实现RecoveryCallback.recover() 方法。

那么问题来了,什么情况下,才能触发重试机制呢???

是异常,源码里给了注释:

追踪源码:

从源码中可以看到,他是通过传递的重试策略,判断是否可以重试。该案例中没有设置重试策略,故使用的是默认的重试策略(SimpleRetryPolicy)。

从spring框中可以看出,提供了11种重试策略:

默认的重试策略对于canRetry()的逻辑是这样的:

从这里我们就可看出是通过异常触发重试策略的。

    RetryTemplate 默认提供了简单测重试机制,为了满足多变的业务场景,我们可以定制属于自己的重试框架,比如监听器,不同的重试策略等。

6、扩展

Google提供的重试框架更灵活一些、更轻量级一些。可以支持线程池、以及多种条件触发重试机制。这里有一个小demo,就不做源码的分析了。
@Test
public void retry02() {
	Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
			.retryIfResult(Predicates.equalTo(false))
			.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
			.withStopStrategy(StopStrategies.stopAfterAttempt(3))
			.build();


	try {
		RetryerCallable<Boolean> wrap = retryer.wrap(new Callable<Boolean>() {
			@Override
			public Boolean call() throws Exception {
				System.out.println("dosomething>>>>>>>>>:" + DateUtils.formatDate(new Date()));
				return false;
			}
		});

		ExecutorService executorService = Executors.newFixedThreadPool(1);
		Future<Boolean> submit = executorService.submit(wrap);
		submit.get();
	}catch (Exception e){
		System.out.println("opver");
	}

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智_永无止境

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值