Spring-retry 1.1.4重试功能
来源:互联网 发布:淘宝客服退换货汇总表 编辑:程序博客网 时间:2024/06/09 12:08
在实际项目中,经常需要在某种情况下对调用的方法进行重试,例如超时重试。通过Spring-retry能简化重试功能的实现,并实现更多样的重试操作。
Spring-retry提供的RetryOperations接口,定义如下:
public interface RetryOperations { <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback) throws E; <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback, RecoveryCallback<T> recoveryCallback) throws E; <T, E extends Throwable> T execute(RetryCallback<T, E> retryCallback, RecoveryCallback<T> recoveryCallback, RetryState retryState) throws E;}
调用者通过传入RetryCallback来完成调用者的正常调用和重试操作;如果callback执行失败(抛出某些异常),那么会按照调用者设定的策略进行重试;重试操作直到成功,或根据使用者设定的条件而退出;也可以传入recoveryCallback来完成兜底操作。Spring-retry提供了RetryOperations接口的实现类RetryTemplate。通过RetryTemplate来完成重试,下面是使用RetryTemplate重试的一个简单例子。
public class Main { public static void main(String[] args) throws Exception { RetryTemplate template = new RetryTemplate(); TimeoutRetryPolicy policy = new TimeoutRetryPolicy(); template.setRetryPolicy(policy); String result = template.execute( new RetryCallback<String, Exception>() { public String doWithRetry(RetryContext arg0) throws Exception { return "Retry"; } } ); System.out.println(result); }}代码定义了TimeoutRetryPolicy策略,TimeoutRetryPolicy超时时间默认是1秒。TimeoutRetryPolicy超时是指在execute方法内部,从open操作开始到调用TimeoutRetryPolicy的canRetry方法这之间所经过的时间。这段时间未超过TimeoutRetryPolicy定义的超时时间,那么执行操作,否则抛出异常。
当重试执行完闭,操作还未成为,那么可以通过RecoveryCallback完成一些失败事后处理。
public class Main { public static void main(String[] args) throws Exception { RetryTemplate template = new RetryTemplate(); SimpleRetryPolicy policy = new SimpleRetryPolicy(); policy.setMaxAttempts(2); template.setRetryPolicy(policy); String result = template.execute( new RetryCallback<String, Exception>() { public String doWithRetry(RetryContext arg0) throws Exception { throw new NullPointerException("nullPointerException"); } } , new RecoveryCallback<String>() { public String recover(RetryContext context) throws Exception { return "recovery callback"; } } ); System.out.println(result); }}上面的代码重试两次后,仍然失败,RecoveryCallback被调用,返回”recovery callback”。如果没有定义RecoveryCallback,那么重试2次后,将会抛出异常。
一、重试策略
1、SimpleRetryPolicy 策略
该策略定义了对指定的异常进行若干次重试。默认情况下,对Exception异常及其子类重试3次。如果创建SimpleRetryPolicy并指定重试异常map,可以选择性重试或不进行重试。下面的代码定义了对TimeOutException进行重试。
public static void main(String[] args) throws Exception { RetryTemplate template = new RetryTemplate(); Map<Class<? extends Throwable>, Boolean> maps = new HashMap<Class<? extends Throwable>, Boolean>(); maps.put(TimeoutException.class, true); SimpleRetryPolicy policy2 = new SimpleRetryPolicy(2, maps); template.setRetryPolicy(policy2); new RetryCallback<String, Exception>() { public String doWithRetry(RetryContext arg0) throws Exception { throw new TimeoutException("TimeoutException"); } } , new RecoveryCallback<String>() { public String recover(RetryContext context) throws Exception { return "recovery callback"; } } ); System.out.println(result); }当Map中的的value为false,那么执行方法,随后抛出异常不进行重试。
2、NeverRetryPolicy 策略
执行一次待执行操作,若出现异常后不进行重试。
3、AlwaysRetryPolicy 策略
异常后一直重试直到成功。
4、TimeoutRetryPolicy 策略
在执行execute方法时从open操作开始到调用TimeoutRetryPolicy的canRetry方法这之间所经过的时间。这段时间未超过TimeoutRetryPolicy定义的超时时间,那么执行操作,否则抛出异常。
5、ExceptionClassifierRetryPolicy 策略
根据产生的异常选择重试策略。
Map<Class<? extends Throwable>, RetryPolicy> policyMap = new HashMap<Class<? extends Throwable>, RetryPolicy>(); policyMap.put(TimeoutException.class, new AlwaysRetryPolicy()); policyMap.put(NullPointerException.class, new NeverRetryPolicy()); policy.setPolicyMap(policyMap);通过PolicyMap定义异常及其重试策略。下面的代码在抛出NullPointerException采用NeverRetryPolicy策略,而TimeoutException采用AlwaysRetryPolicy。
public class Main { public static void main(String[] args) throws Exception { RetryTemplate template = new RetryTemplate(); ExceptionClassifierRetryPolicy policy = new ExceptionClassifierRetryPolicy(); Map<Class<? extends Throwable>, RetryPolicy> policyMap = new HashMap<Class<? extends Throwable>, RetryPolicy>(); policyMap.put(TimeoutException.class, new AlwaysRetryPolicy()); policyMap.put(NullPointerException.class, new NeverRetryPolicy()); policy.setPolicyMap(policyMap); template.setRetryPolicy(policy); String result = template.execute( new RetryCallback<String, Exception>() { public String doWithRetry(RetryContext arg0) throws Exception { if(arg0.getRetryCount() >= 2) { Thread.sleep(1000); throw new NullPointerException(); } throw new TimeoutException("TimeoutException"); } } , new RecoveryCallback<String>() { public String recover(RetryContext context) throws Exception { return "recovery callback"; } } ); System.out.println(result); }}此外可以通过setExceptionClassifier来为异常指定重试策略。
Classifier<Throwable, RetryPolicy> exceptionClassifier = new Classifier<Throwable, RetryPolicy>(){ public RetryPolicy classify(Throwable classifiable) { if(classifiable instanceof TimeoutException) return new SimpleRetryPolicy(); return new NeverRetryPolicy(); } }; policy.setExceptionClassifier(exceptionClassifier);setPolicyMap与setExceptionClassifier使用一个即可。
6、CompositeRetryPolicy 策略
用户指定一组策略,随后根据optimistic选项来确认如何重试。
下面的代码中创建CompositeRetryPolicy策略,并创建了RetryPolicy数组,数组有两个具体策略SimpleRetryPolicy与AlwaysRetryPolicy。当CompositeRetryPolicy设置optimistic为true时,Spring-retry会顺序遍历RetryPolicy[]数组,如果有一个重试策略可重试,例如SimpleRetryPolicy没有达到重试次数,那么就会进行重试。 如果optimistic选项设置为false。那么有一个重试策略无法重试,那么就不进行重试。例如SimpleRetryPolicy达到重试次数不能再重试,而AlwaysRetryPolicy可以重试,那么最终是无法重试的。
public class Main { public static void main(String[] args) throws Exception { RetryTemplate template = new RetryTemplate(); CompositeRetryPolicy policy = new CompositeRetryPolicy(); RetryPolicy[] polices = {new SimpleRetryPolicy(), new AlwaysRetryPolicy()}; policy.setPolicies(polices); policy.setOptimistic(true); template.setRetryPolicy(policy); String result = template.execute( new RetryCallback<String, Exception>() { public String doWithRetry(RetryContext arg0) throws Exception { if(arg0.getRetryCount() >= 2) { Thread.sleep(1000); throw new NullPointerException(); } throw new TimeoutException("TimeoutException"); } } , new RecoveryCallback<String>() { public String recover(RetryContext context) throws Exception { return "recovery callback"; } } ); System.out.println(result); }}上述代码,设置setOptimistic(true),而AlwaysRetryPolicy一直可重试,那么最终可以不断进行重试。
二、退避(BackOff)策略:
当操作执行失败时,根据设置的重试策略进行重试。通过BackoffPolicy可以设定再次重试的时间间隔。
public interface BackOffPolicy { BackOffContext start(RetryContext context); void backOff(BackOffContext backOffContext) throws BackOffInterruptedException;}BackOffPolicy接口的实现具体的实现有如下几种。
1、StatelessBackoffPolicy下的3个实现类
1)org.springframework.retry.backoff.FixedBackOffPolicy
在等待一段固定的时间后,再进行重试。默认为1秒。
2)org.springframework.retry.backoff.NoBackOffPolicy
实现了空方法,因此采用次策略,重试不会等待。这也是RetryTemplate采用的默认退避(backOff)策略。
private volatile BackOffPolicy backOffPolicy = new NoBackOffPolicy();3)org.springframework.retry.backoff.UniformRandomBackOffPolicy
均匀随机退避策略,等待时间为 最小退避时间 + [0,最大退避时间 - 最小退避时间)间的一个随机数,如果最大退避时间等于最小退避时间那么等待时间为0。
2、SleepingbackOffPolicy的下的4个实现类
1)org.springframework.retry.backoff.ExponentialBackOffPolicy
指数退避策略 ,每次等待时间为 等待时间 = 等待时间 * N ,即每次等待时间为上一次的N倍。如果等待时间超过最大等待时间,那么以后的等待时间为最大等待时间。
ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy(); exponentialBackOffPolicy.setInitialInterval(1500); exponentialBackOffPolicy.setMultiplier(2); exponentialBackOffPolicy.setMaxInterval(6000);上面的代码创建了一个ExponentialBackOffPolicy,初始时间间隔为1500毫秒,N = 2,¸最大间隔为6000毫秒,那么从第4次重试开始,以后每次等待时间都为6000毫秒。
2)org.springframework.retry.backoff.ExponentialRandomBackOffPolicy
指数随机策略,该类是ExponentialBackOffPolicy的子类,计算等待时间的算法为
@Override public synchronized long getSleepAndIncrement() { long next = super.getSleepAndIncrement(); next = (long)(next*(1 + r.nextFloat()*(getMultiplier()-1))); return next; }该方法调用ExponentialBackOffPolicy方法,返回等待时间,随后next*(Multiplier – 1)最为等待时间。 即 [next,next* Multiplier) 之间的一个随机数。
3)org.springframework.retry.backoff.FixedBackOffPolicy
4)org.springframework.retry.backoff.UniformRandomBackOffPolicy
这两个类与StatelessBackoffPolicy的同名实现类返回等待时间的方法是一致的。而两者的主要区别是,SleepingbackOffPolicy可以设置用户定义的Sleeper。
public interface Sleeper { void sleep(long backOffPeriod) throws InterruptedException;}
通过监听器,可以在重试操作的某些位置嵌入调用者定义的一些操作,以便在某些场景触发。
public class Main { public static void main(String[] args) throws Exception { RetryTemplate template = new RetryTemplate(); ExponentialRandomBackOffPolicy exponentialBackOffPolicy = new ExponentialRandomBackOffPolicy(); exponentialBackOffPolicy.setInitialInterval(1500); exponentialBackOffPolicy.setMultiplier(2); exponentialBackOffPolicy.setMaxInterval(6000); CompositeRetryPolicy policy = new CompositeRetryPolicy(); RetryPolicy[] polices = {new SimpleRetryPolicy(), new AlwaysRetryPolicy()}; policy.setPolicies(polices); policy.setOptimistic(true); template.setRetryPolicy(policy); template.setBackOffPolicy(exponentialBackOffPolicy); template.registerListener(new RetryListener() { public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { System.out.println("open"); return true; } public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { System.out.println("onError"); } public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { System.out.println("close"); } }); template.registerListener(new RetryListener() { public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { System.out.println("open2"); return true; } public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { System.out.println("onError2"); } public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { System.out.println("close2"); } }); String result = template.execute( new RetryCallback<String, Exception>() { public String doWithRetry(RetryContext arg0) throws Exception { arg0.getAttribute(""); if(arg0.getRetryCount() >= 2) { throw new NullPointerException(); } throw new TimeoutException("TimeoutException"); } } ); System.out.println(result); }}
上述代码注册了两个Listener,Listener中的三个实现方法,onError,open,close会在执行重试操作时被调用,在RetryTemplate中doOpenInterceptors,doCloseInterceptors,doOnErrorInterceptors会调用监听器对应的open,close,onError 方法。
doOpenInterceptors方法在第一次重试之前会被调用,如果该方法返回true,则会继续向下直接,如果返回false,则抛出异常,停止重试。
doCloseInterceptors 会在重试操作执行完毕后调用。
doOnErrorInterceptors 在抛出异常后执行,
当注册多个Listener时,open方法按会按Listener的注册顺序调用,而onError和close则按Listener注册的顺序逆序调用。
- Spring-retry 1.1.4重试功能
- 使用Spring-retry 1.1.4完成重试功能
- Spring重试支持Spring Retry
- Spring重试支持Spring Retry
- 重试框架Spring retry实践
- spring-retry注解方式使用(断路器,重试)
- 利用Spring-Retry定制化你的RPC重试
- Retry重试机制
- Retry重试机制
- Retry重试机制
- spring-retry重试与熔断详解—《亿级流量》内容补充
- spring-retry
- spring-retry
- Cloud Design Pattern - Retry Pattern(重试模式)
- spring-boot+spring-retry
- Spring retry基本使用
- Spring Retry中文文档
- Spring Retry实现原理
- android app -- 关于listview的几种用法(复用,不复用,半复用)解决item状态改变的问题
- python编程练习---一行代码实现计算器功能
- SpringBoot-自动配置1
- ansible-playbook实战之部署redis+sentinel+twemproxy
- java类中方法中的参数过多如何处理
- Spring-retry 1.1.4重试功能
- 【jQuery】jQuery官方基本教程的学习笔记1-核心Core
- 装箱问题
- Linux下Solr4.10.4搜索引擎的安装与部署图文详解
- Centos7安装mysql
- 菜鸟先飞之二维码zxing生成
- Hystrix服务容错降级使用
- 大型工程代码如何防止头文件被重复包含
- IntelliJ Idea 常用快捷键列表