`
raymond.chen
  • 浏览: 1418363 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

spring retry框架的使用

 
阅读更多

spring retry是从spring batch独立出来的一个功能,主要实现了重试和熔断。

 

重试策略

       NeverRetryPolicy:只调用RetryCallback一次,不重试

       SimpleRetryPolicy:重试n次,默认3次,也是RetryTemplate模板默认的策略。很常用

       ExceptionClassifierRetryPolicy:可以根据不同的异常,执行不同的重试策略,很常用

       TimeoutRetryPolicy:在n毫秒内不断进行重试,超过这个时间后停止重试

       CircuitBreakerRetryPolicy:熔断功能的重试

       CompositeRetryPolicy:将不同的策略组合起来,有悲观组合和乐观组合。悲观默认重试,有不重试的策略则不重试。乐观默认不重试,有需要重试的策略则重试

       AlwaysRetryPolicy:无限重试,最好不要用

 

退避策略:每次重试是立即重试还是等待一段时间后重试

       NoBackOffPolicy:不回避

 

       FixedBackOffPolicy:n毫秒退避后再进行重试,需设置参数sleeper和backOffPeriod,sleeper指定等待策略,默认是Thread.sleep,即线程休眠,backOffPeriod指定休眠时间,默认1秒

 

       UniformRandomBackOffPolicy:随机选择一个[n,m](如20ms,40ms)回避时间回避后,然后再重试,需设置sleeper、minBackOffPeriod和maxBackOffPeriod,该策略在[minBackOffPeriod,maxBackOffPeriod之间取一个随机休眠时间,minBackOffPeriod默认500毫秒,maxBackOffPeriod默认1500毫秒

 

       ExponentialBackOffPolicy:指数退避策略,需设置参数sleeper、initialInterval、maxInterval和multiplier,initialInterval指定初始休眠时间,默认100毫秒,maxInterval指定最大休眠时间,默认30秒,multiplier指定乘数,即下一次休眠时间为当前休眠时间*multiplier

 

       ExponentialRandomBackOffPolicy:随机指数退避策略,引入随机乘数可以实现随机乘数回退

 

无状态重试是指重试在一个线程上下文中完成的重试,反之不在一个线程上下文完成重试的就是有状态重试。需要有状态重试的情况通常有两种:事务回滚和熔断。

 

主要的依赖包:

<dependency>
	<groupId>org.springframework.retry</groupId>
	<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
</dependency>

<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.1</version>
</dependency>

 

范例:

public void retry1() throws Exception {
	RetryTemplate retryTemplate = new RetryTemplate();

	//重试策略
	SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
	retryPolicy.setMaxAttempts(3); //最多重试3次
	
//        TimeoutRetryPolicy retryPolicy = new TimeoutRetryPolicy();
//        retryPolicy.setTimeout(5000L); //超时重试:在指定时间内可以不断重试
	
	//退避策略
	FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
	fixedBackOffPolicy.setBackOffPeriod(500); //间隔1000毫秒

	retryTemplate.setRetryPolicy(retryPolicy);
	retryTemplate.setBackOffPolicy(fixedBackOffPolicy);

	//重试操作
	final RetryCallback<Boolean, Exception> retryCallback = new RetryCallback<Boolean, Exception>() {
		@Override
		public Boolean doWithRetry(RetryContext retryContext) throws Exception {
			System.out.println(String.format("retry count: %s", retryContext.getRetryCount()+1));
			throwError(retryContext.getRetryCount()+1);
			return true;
		}
	};
	
	//重试失败后执行兜底回调
	final RecoveryCallback<Boolean> recoveryCallback = new RecoveryCallback<Boolean>() {
		@Override
		public Boolean recover(RetryContext retryContext) throws Exception {
			System.out.println(String.format("after retry: %s, recovery method called!", retryContext.getRetryCount()+1));
			return false;
		}
	};
	
	Boolean result = retryTemplate.execute(retryCallback, recoveryCallback);
	
	System.out.println(String.format("execute result: %s", result));
}

private void throwError(int retryCount) throws Exception {
	if(retryCount < 20){
		throw new Exception("");
	}
}

 

在Springboot环境下使用spring retry

主要注解类:

       @EnableRetry:启用重试机制,proxyTargetClass属性为true时(默认false)使用CGLIB代理

 

       @Retryable:在需要被重试的方法上加上该注解类 

                maxAttempts 最大重试次数。默认3次 

                vaue 指定要重试的异常。默认为空 

                backoff 重试等待策略。默认使用@Backoff注解

                include 指定处理的异常类。默认为空 

                exclude 指定不需要处理的异常。默认为空

 

        @Backoff:重试回退策略(立即重试还是等待一会再重试) 

                delay 延迟重试的毫秒数

                multiplier 延迟间隔时间的倍数

 

                不设置参数时,默认使用FixedBackOffPolicy,重试等待1000ms 

                只设置delay()属性时,使用FixedBackOffPolicy,重试等待指定的毫秒数 

                当设置delay()和maxDealy()属性时,重试等待在这两个值之间均态分布 

                使用delay(),maxDealy()和multiplier()属性时,使用ExponentialBackOffPolicy 

                当设置multiplier()属性不等于0时,同时也设置了random()属性时,使用ExponentialRandomBackOffPolicy

 

       @Recover: 用于方法。

                用于@Retryable失败时的“兜底”处理方法 

 

       @CircuitBreaker:用于方法,实现熔断模式。 

                include 指定处理的异常类。默认为空 

                exclude指定不需要处理的异常。默认为空 

                vaue指定要重试的异常。默认为空 

                maxAttempts 最大重试次数。默认3次 

                openTimeout 配置熔断器打开的超时时间,默认5s,当超过openTimeout之后熔断器电路变成半打开状态(只要有一次重试成功,则闭合电路) 

                resetTimeout 配置熔断器重新闭合的超时时间,默认20s,超过这个时间断路器关闭

 

定义服务类:

/**
 * 使用了@Retryable的方法不能在本类被调用,不然重试机制不会生效
 * @Retryable 跟 @Recover 标注的方法,返回值必须相同。
 * 使用了@Retryable的方法里面不能使用try...catch包裹,要在方法上抛出异常,不然不会触发
 */
@Service
public class RemoteService {
	/**
	 * 调用该方法过程中发生RemoteAccessException异常时触发重试机制,重试次数达到指定值后,触发@Recover标注的方法
	 */
	@Retryable(value=RemoteAccessException.class, maxAttempts=3, backoff=@Backoff(delay=500, multiplier=1.5))
	public void call() throws Exception {
		throw new RemoteAccessException("invoke RemoteService.call() error");
	}
	
	/**
	 * 退避方法
	 */
	@Recover
	public void recover(RemoteAccessException ex) {
		System.out.println(ex.toString());
	}
	
	/**
	 * Exception异常没有对应的退避方法
	 */
	@Retryable(value=Exception.class, maxAttempts=3)
	public boolean pay(int num) throws Exception {
		System.out.println(LocalDateTime.now().toString());
		if(num < 0){
			throw new Exception("num must be greater than 0");
		}
		return true;
	}
}

 

 在启动类引用服务类进行测试:

@SpringBootApplication()
@RestController
@EnableRetry //启用重试机制
public class Main{
	@Autowired
	private RemoteService remoteService;
	
	public static void main(String[] args){
		SpringApplication.run(Main.class, args);
	}
	
	@GetMapping("/index")
	public String index(){
		try {
			remoteService.call();
			remoteService.pay(-1);
		} catch (Exception ex) {
			System.out.println(ex.toString());
		}
		return LocalDateTime.now().toString();
	}
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics