spring-retry是spring社区的一个成员,它提供了一种对失败操作进行自动重试的能力,可以作为某些瞬时错误(例如短暂的网络抖动)的解决方案。

作为spring生态的一部分,spring-retry自然地支持声明式(Declarative)方式使用。此外,它也支持命令式(Impertive)方式在代码里直接调用。

1. 项目集成

引入依赖:

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

它的版本交给spring boot管理,以获得与spring良好的兼容性。

项目当前使用的是spring-boot版本为1.5.13.RELEASE,它管理的spring-retry版本是1.2.2.RELEASE。

2. 声明式使用方式

  1. 在spring boot启动类上增加@EnableRetry注解:

    @EnableRetry(proxyTargetClass = true)
    @SpringBootApplication
    public class TestApplication {public static void main(String[] args) {SpringApplication.run(TestApplication.class, args);}
    }
    

    该注解的proxyTargetClass属性默认为false,表示使用JDK的动态代理。如果设置为true,则表示使用CGLIB作为动态代理。

  2. 在需要重试的方法上,增加@Retryable注解:

    @Service
    @Slf4j
    public class RetryAnnotationTest {@Retryable(value = {RemoteAccessException.class}, maxAttempts = 5, backoff = @Backoff(delay = 1000L), recover = "recoverCall")public boolean call(String param){System.out.println(new Date());return RetryTask.retryTask(param);}@Recoverpublic boolean recoverCall(Exception e,String param) {log.error("达到最大重试次数,或抛出了一个没有指定进行重试的异常:", e);return false;}
    }
    

    如上示例中,当call方法抛出RemoteAccessException异常时,spring retry会重新调用call方法,重试次数为5次,两次重试之间间隔为1s。

    如果超过最大重试次数仍未成功,或者抛出非RemoteAccessException异常,则调用recoverCall方法。

    注:@Retryable注解也可以作用在类上,作用在类上之后,spring retry会对类的全部方法进行重试。

3. 命令式使用方式

  1. 配置RetryTemplate:

    @Configuration
    public class SpringRetryConfig {@Bean("retryTemplateFixed")public RetryTemplate retryTemplateFixed() {// 1.重试策略// 触发条件Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();exceptionMap.put(RemoteAccessException.class, true);// 重试次数设置为3次int maxAttempts = 3;SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxAttempts, exceptionMap);// 2.重试间隔设置为1秒FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();backOffPolicy.setBackOffPeriod(1000);// 3.构造RetryTemplateRetryTemplate retryTemplate = new RetryTemplate();retryTemplate.setRetryPolicy(retryPolicy);retryTemplate.setBackOffPolicy(backOffPolicy);return retryTemplate;}@Bean("retryTemplate")public RetryTemplate retryTemplate() {// 定义简易重试策略,最大重试次数为3次,重试间隔为3sreturn RetryTemplate.builder().maxAttempts(3).fixedBackoff(3000).retryOn(RuntimeException.class).build();}}
    

    注:可以配置多个RetryTemplate,用以适应不同重试场景。

    spring retry支持的重试策略和退避策略如下:

    @Bean("retryTemplateDemo")
    public RetryTemplate retryTemplateDemo() {// 1.重试策略// 不重试NeverRetryPolicy neverRetryPolicy = new NeverRetryPolicy();// 无限重试AlwaysRetryPolicy alwaysRetryPolicy = new AlwaysRetryPolicy();// 设置不同异常的重试策略,类似组合重试策略,区别在于这里只区分不同异常的重试ExceptionClassifierRetryPolicy exceptionClassifierRetryPolicy = new ExceptionClassifierRetryPolicy();final Map<Class<? extends Throwable>, RetryPolicy> policyMap = new HashMap<>(3);policyMap.put(IOException.class, alwaysRetryPolicy);policyMap.put(InterruptedIOException.class, neverRetryPolicy);policyMap.put(UnknownHostException.class, neverRetryPolicy);exceptionClassifierRetryPolicy.setPolicyMap(policyMap);// 固定次数重试,默认最大重试次数为5次,RetryTemplate默认重试策略SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();simpleRetryPolicy.setMaxAttempts(5);// 超时时间重试,默认超时时间为1秒,在指定的超时时间内重试TimeoutRetryPolicy timeoutRetryPolicy = new TimeoutRetryPolicy();timeoutRetryPolicy.setTimeout(3000);/** 组合重试策略,有两种组合方式:*  1.悲观默认重试,有不重试的策略则不重试。*  2.乐观默认不重试,有需要重试的策略则重试。*/CompositeRetryPolicy compositeRetryPolicy = new CompositeRetryPolicy();compositeRetryPolicy.setOptimistic(true);compositeRetryPolicy.setPolicies(new RetryPolicy[]{simpleRetryPolicy, timeoutRetryPolicy});// 有熔断功能的重试CircuitBreakerRetryPolicy circuitBreakerRetryPolicy = new CircuitBreakerRetryPolicy(compositeRetryPolicy);// 5s内失败10次,则开启熔断circuitBreakerRetryPolicy.setOpenTimeout(5000);// 10s之后熔断恢复circuitBreakerRetryPolicy.setResetTimeout(10000);// 2.退避策略(上一次执行失败之后,间隔多久进行下一次重试)// 立即重试NoBackOffPolicy noBackOffPolicy = new NoBackOffPolicy();// 固定时间后重试,默认1sFixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();fixedBackOffPolicy.setBackOffPeriod(1000);// 随机时间后重试(如下:从500ms到1500ms内取一个随机时间后进行重试)UniformRandomBackOffPolicy uniformRandomBackOffPolicy = new UniformRandomBackOffPolicy();uniformRandomBackOffPolicy.setMinBackOffPeriod(500);uniformRandomBackOffPolicy.setMaxBackOffPeriod(1500);// 指数退避策略(如下:初始休眠时间100ms,最大休眠时间30s,下一次休眠时间为当前休眠时间*2)ExponentialBackOffPolicy exponentialBackOffPolicy = new ExponentialBackOffPolicy();exponentialBackOffPolicy.setInitialInterval(100);exponentialBackOffPolicy.setMaxInterval(30000);exponentialBackOffPolicy.setMultiplier(2);// 随机指数退避策略ExponentialRandomBackOffPolicy exponentialRandomBackOffPolicy = new ExponentialRandomBackOffPolicy();exponentialRandomBackOffPolicy.setInitialInterval(100);exponentialRandomBackOffPolicy.setMaxInterval(30000);exponentialRandomBackOffPolicy.setMultiplier(2);// 3.returnRetryTemplate retryTemplate = new RetryTemplate();retryTemplate.setRetryPolicy(circuitBreakerRetryPolicy);return retryTemplate;
    }
    
  2. 在代码中调用

    @Slf4j
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class RetryTest {// 注入RetryTemplate@Resourceprivate RetryTemplate retryTemplateFixed;@Testpublic void test() {// 执行Boolean execute = retryTemplateFixed.execute(// 重试回调retryContext -> {System.out.println(new Date());boolean b = RetryTask.retryTask("abc");log.info("调用的结果:{}", b);return b;},// 恢复回调(达到最大重试次数,或者抛出不满足重试条件的异常)retryContext -> {log.info("已达到最大重试次数或抛出了不重试的异常~~~");return false;});log.info("执行结果:{}",execute);}}
    
  3. 监听重试过程

    通过实现RetryListener接口,重写open、close、onError这三个方法,既可以完成对重试过程的追踪,也可以添加额外的处理逻辑。

    @Slf4j
    @Component
    public class RetryListenerTemplate implements RetryListener {// 进入重试前调用@Overridepublic <T, E extends Throwable> boolean open(RetryContext retryContext, RetryCallback<T, E> retryCallback) {log.info("--------------------------进入重试方法--------------------------");return true;}// 重试结束后调用@Overridepublic <T, E extends Throwable> void close(RetryContext retryContext, RetryCallback<T, E> retryCallback, Throwable throwable) {log.info("--------------------------重试方法结束--------------------------");}// 捕获到异常时调用@Overridepublic <T, E extends Throwable> void onError(RetryContext retryContext, RetryCallback<T, E> retryCallback, Throwable throwable) {log.info("--------------------------第" + retryContext.getRetryCount() + "次重试--------------------------");log.error(throwable.getMessage(), throwable);
    }
    }
    

    或者,通过继承RetryListenerSupport,也可以从open、close、onError这三个方法中,选择性的重写。

    public class RetryListener4Open extends RetryListenerSupport {@Overridepublic <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {return super.open(context, callback);}
    }
    

    在实例化RetryTemplate时,配置上该RetryListener实例即可。

    retryTemplate.setListeners(new RetryListener[] {retryListenerTemplate});
    

    注:

    1. V2.0版本以后,新增一个doOnSuccess方法,可以在调用成功之后,根据返回的结果值,来决定是否要进行重试。
    2. 每个RetryTemplate可以注册多个监听器,其中onOpen、onClose方法按照注册顺序执行,onError按照注册顺序的相反顺序执行。

参考资料:

  1. Spring-Retry 和 Guava-Retry
  2. Spring Retry Github地址

重试组件 Spring Retry相关推荐

  1. java retry_Spring重试支持Spring Retry的方法

    本文介绍了Spring重试支持Spring Retry的方法,分享给大家,具体如下: 第一步.引入maven依赖 org.springframework.boot spring-boot-starte ...

  2. Spring异常重试框架Spring Retry

    在调用第三方接口或者使用mq时,会出现网络抖动,连接超时等网络异常,所以需要重试.为了使处理更加健壮并且不太容易出现故障,后续的尝试操作,有时候会帮助失败的操作最后执行成功.例如,由于网络故障或数据库 ...

  3. 重试框架Spring retry实践

    spring retry是从spring batch独立出来的一个能功能,主要实现了重试和熔断.对于重试是有场景限制的,不是什么场景都适合重试,比如参数校验不合法.写操作等(要考虑写是否幂等)都不适合 ...

  4. java retry_Spring异常重试框架Spring Retry详解

    Spring Retry支持集成到Spring或者Spring Boot项目中,而它支持AOP的切面注入写法,所以在引入时必须引入aspectjweaver.jar包. 快速集成的代码样例: @Con ...

  5. Spring异常重试机制 - Spring Retry

    目录 一 . 引入依赖 二 . 在启用类或业务类上添加@EnableRetry注解启用重试机制(在启用类上添加全局有效 , 在业务类上添加仅当前有效) 三 . 使用@Retryable实现重试 四 . ...

  6. 针对Spring的Spring Retry 我发现了这样一个大家都不知道的技巧!

    外部服务对于调用者来说一般都是不可靠的,尤其是在网络环境比较差的情况下,网络抖动很容易导致请求超时等异常情况,这时候就需要使用失败重试策略重新调用 API 接口来获取.重试策略在服务治理方面也有很广泛 ...

  7. 高级JAVA - 手写简单的重试组件学习Spring Retry

    目录 一 . 定义注解 二 . 利用cglib代理扩展重试业务 三 . 编写代理类 , 使用自定义的XRetryInterceptor作为拦截器 四 . 编写相关业务方法 , 测试代码 五 . 测试结 ...

  8. foxmail邮件加载失败重试_java retry(重试) spring retry, guava retrying 详解

    系列说明 java retry 的一步步实现机制. java-retry 源码地址 情景导入 简单的需求 产品经理:实现一个按条件,查询用户信息的服务. 小明:好的.没问题. 代码 UserServi ...

  9. java retry(重试) spring retry, guava retrying 详解

    转载 自 http://blog.51cto.com/9250070/2156431 系列说明 java retry 的一步步实现机制. java-retry 源码地址 情景导入 简单的需求 产品经理 ...

最新文章

  1. 《EE Times》评出2020年全球最值得关注的18家传感器公司
  2. 后端数据操作超时_数据分析在知乎商业质量保障中的初步实践
  3. 微信:禁用小程序跳转 App;华为商城上架 PlayStation 5;币安涉及洗钱被美监管调查
  4. [整理+原创]ubuntu Thunderbird Mail设置自动提醒
  5. 当女朋友问你会不会出轨的时候,该怎么回答?
  6. 快速上手Tomcat
  7. 信访问题归并处理_最高法判例:行政机关以信访形式处理履行法定职责问题的起诉期限...
  8. c语言 一元二次函数,计算一元二次函数的根,大家看看那里有错了。。。。
  9. eclipse你的主机中的软件中止了一个已建立的连接。_如何备份/恢复一个基于Windows系统的操作面板?...
  10. matlab已知xyz拟合标定map,matlab练习题
  11. asp.net C#后台实现下载文件的几种方法
  12. winform通过WebClient调用api接口
  13. 全国计算机三级嵌入式资料
  14. 计算机用户名取名,重命名电脑用户名
  15. 如何理解移动数据和移动计算
  16. java——财务支票大写汉字转换
  17. CPU 与 GPU 渲染:如何选择及原因?
  18. Cesium之地形(1)
  19. MCUXpresso开发NXP RT1060(3)——移植LVGL到NXP RT1060
  20. Redis-PHP实战篇——常用的使用场景

热门文章

  1. word输入希腊字母
  2. Android 开发实战:点击按钮显示一个带有“取消”和“确定”两个选项的对话框
  3. shell script总结大全
  4. Google-Kythe-Callgraphs
  5. top.location和window.location有什么区别?
  6. 矩阵与矩阵相乘python代码实现
  7. c#方法参数:params
  8. 上海计算机学会2023年3月月赛C++乙组T1卡片游戏
  9. 2007年下半年程序员上午试卷
  10. 也谈如何举办一场成功的技术讲座?