使用Guava retryer优雅的实现接口重调机制

2024-09-03 02:38

本文主要是介绍使用Guava retryer优雅的实现接口重调机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

API 接口调用异常, 网络异常在我们日常开发中经常会遇到,这种情况下我们需要先重试几次调用才能将其标识为错误并在确认错误之后发送异常提醒。guava-retry可以灵活的实现这一功能。Guava retryer在支持重试次数和重试频度控制基础上,能够兼容支持多个异常或者自定义实体对象的重试源定义,让重试功能有更多的灵活性。Guava Retryer也是线程安全的,入口调用逻辑采用的是Java.util.concurrent.Callable的call方法。

使用Guava retryer 很简单,我们只要做以下几步:

Step1、引入Guava-retry  

<guava-retry.version>2.0.0</guava-retry.version>
<dependency><groupId>com.github.rholder</groupId><artifactId>guava-retrying</artifactId><version>${guava-retry.version}</version>
</dependency>

Step2、定义实现Callable接口的方法,以便Guava retryer能够调用

/*** @desc 更新可代理报销人接口* @author jianzhang11* @date 2017/3/31 15:17*/private static Callable<Boolean> updateReimAgentsCall = new Callable<Boolean>() {@Overridepublic Boolean call() throws Exception {String url = ConfigureUtil.get(OaConstants.OA_REIM_AGENT);String result = HttpMethod.post(url, new ArrayList<BasicNameValuePair>());if(StringUtils.isEmpty(result)){throw new RemoteException("获取OA可报销代理人接口异常");}List<OAReimAgents> oaReimAgents = JSON.parseArray(result, OAReimAgents.class);if(CollectionUtils.isNotEmpty(oaReimAgents)){CacheUtil.put(Constants.REIM_AGENT_KEY,oaReimAgents);return true;}return false;}};

Step3、定义Retry对象并设置相关策略

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()//抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。.retryIfException()//返回false也需要重试.retryIfResult(Predicates.equalTo(false))//重调策略.withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))//尝试次数.withStopStrategy(StopStrategies.stopAfterAttempt(3)).build();try {retryer.call(updateReimAgentsCall);} catch (ExecutionException e) {
//            e.printStackTrace();} catch (RetryException e) {logger.error("更新可代理报销人异常,需要发送提醒邮件");}

简单三步就能使用Guava Retryer优雅的实现重调方法。

   接下来对其进行详细说明:  

  RetryerBuilder是一个factory创建者,可以定制设置重试源且可以支持多个重试源,可以配置重试次数或重试超时时间,以及可以配置等待时间间隔,创建重试者Retryer实例。

  RetryerBuilder的重试源支持Exception异常对象 和自定义断言对象,通过retryIfException 和retryIfResult设置,同时支持多个且能兼容。

  retryIfException,抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。

  retryIfRuntimeException只会在抛runtime异常的时候才重试,checked异常和error都不重试。

  retryIfExceptionOfType允许我们只在发生特定异常的时候才重试,比如NullPointerException和IllegalStateException都属于runtime异常,也包括自定义的error

  如: 

.retryIfExceptionOfType(Error.class)// 只在抛出error重试

当然我们还可以在只有出现指定的异常的时候才重试,如:  

.retryIfExceptionOfType(IllegalStateException.class)  
.retryIfExceptionOfType(NullPointerException.class)  

或者通过Predicate实现

.retryIfException(Predicates.or(Predicates.instanceOf(NullPointerException.class),  Predicates.instanceOf(IllegalStateException.class))) 

retryIfResult可以指定你的Callable方法在返回值的时候进行重试,如  

// 返回false重试 
.retryIfResult(Predicates.equalTo(false))  
//以_error结尾才重试 
.retryIfResult(Predicates.containsPattern("_error$"))  

当发生重试之后,假如我们需要做一些额外的处理动作,比如发个告警邮件啥的,那么可以使用RetryListener。每次重试之后,guava-retrying会自动回调我们注册的监听。可以注册多个RetryListener,会按照注册顺序依次调用。

import com.github.rholder.retry.Attempt;  
import com.github.rholder.retry.RetryListener;  import java.util.concurrent.ExecutionException;  public class MyRetryListener<Boolean> implements RetryListener {  @Override  public <Boolean> void onRetry(Attempt<Boolean> attempt) {  // 第几次重试,(注意:第一次重试其实是第一次调用)  System.out.print("[retry]time=" + attempt.getAttemptNumber());  // 距离第一次重试的延迟  System.out.print(",delay=" + attempt.getDelaySinceFirstAttempt());  // 重试结果: 是异常终止, 还是正常返回  System.out.print(",hasException=" + attempt.hasException());  System.out.print(",hasResult=" + attempt.hasResult());  // 是什么原因导致异常  if (attempt.hasException()) {  System.out.print(",causeBy=" + attempt.getExceptionCause().toString());  } else {  // 正常返回时的结果  System.out.print(",result=" + attempt.getResult());  }  // bad practice: 增加了额外的异常处理代码  try {  Boolean result = attempt.get();  System.out.print(",rude get=" + result);  } catch (ExecutionException e) {  System.err.println("this attempt produce exception." + e.getCause().toString());  }  System.out.println();  }  
}

接下来在Retry对象中指定监听:  

.withRetryListener(new MyRetryListener<>())  

下面就是运行代码进行测试了。

这篇关于使用Guava retryer优雅的实现接口重调机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131787

相关文章

springboot security快速使用示例详解

《springbootsecurity快速使用示例详解》:本文主要介绍springbootsecurity快速使用示例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录创www.chinasem.cn建spring boot项目生成脚手架配置依赖接口示例代码项目结构启用s

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

java中使用POI生成Excel并导出过程

《java中使用POI生成Excel并导出过程》:本文主要介绍java中使用POI生成Excel并导出过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求说明及实现方式需求完成通用代码版本1版本2结果展示type参数为atype参数为b总结注:本文章中代码均为

java中反射(Reflection)机制举例详解

《java中反射(Reflection)机制举例详解》Java中的反射机制是指Java程序在运行期间可以获取到一个对象的全部信息,:本文主要介绍java中反射(Reflection)机制的相关资料... 目录一、什么是反射?二、反射的用途三、获取Class对象四、Class类型的对象使用场景1五、Class

idea中创建新类时自动添加注释的实现

《idea中创建新类时自动添加注释的实现》在每次使用idea创建一个新类时,过了一段时间发现看不懂这个类是用来干嘛的,为了解决这个问题,我们可以设置在创建一个新类时自动添加注释,帮助我们理解这个类的用... 目录前言:详细操作:步骤一:点击上方的 文件(File),点击&nbmyHIgsp;设置(Setti

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

一文详解如何从零构建Spring Boot Starter并实现整合

《一文详解如何从零构建SpringBootStarter并实现整合》SpringBoot是一个开源的Java基础框架,用于创建独立、生产级的基于Spring框架的应用程序,:本文主要介绍如何从... 目录一、Spring Boot Starter的核心价值二、Starter项目创建全流程2.1 项目初始化(