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>() {
        @Override
        public 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优雅的实现接口重调机制的更多相关文章

  1. 使用Guava retryer优雅的实现接口重试机制

    转载自: 使用Guava retrying优雅的实现接口重调机制 Guava retrying:基于 guava 的重试组件 实际项目中,为了考虑网络抖动,加锁并发冲突等场景,我们经常需要对异常操作进 ...

  2. Guava Retryer实现接口重试

    前言 小黑在开发中遇到个问题,我负责的模块需要调用某个三方服务接口查询信息,查询结果直接影响后续业务逻辑的处理: 这个接口偶尔会因网络问题出现超时,导致我的业务逻辑无法继续处理: 这个问题该如何解决呢 ...

  3. 优雅实现INotifyPropertyChanged接口——利用Lambda表达式

    原文:优雅实现INotifyPropertyChanged接口--利用Lambda表达式 参考文章 在14年的时候,曾经读过上面的参考文章,不过当时并没有怎么理解,慢慢地也就将这篇文章忘诸脑后了. 直 ...

  4. 基于netty实现的长连接,心跳机制及重连机制

    技术:maven3.0.5 + netty4.1.33 + jdk1.8   概述 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速 ...

  5. Dubbo超时和重连机制

    dubbo启动时默认有重试机制和超时机制.超时机制的规则是如果在一定的时间内,provider没有返回,则认为本次调用失败,重试机制在出现调用失败时,会再次调用.如果在配置的调用次数内都失败,则认为此 ...

  6. testng增加失败重跑机制

    注: 以下内容引自 http://www.yeetrack.com/?p=1015 testng增加失败重跑机制 Posted on 2014 年 10 月 31 日 使用Testng框架搭建自动测试 ...

  7. Netty 之 Netty生产级的心跳和重连机制

    https://blog.csdn.net/z69183787/article/details/52625095 最近工作比较忙,但闲暇之余还是看了阿里的冯家春(fengjiachun)的github ...

  8. Netty生产级的心跳和重连机制

    今天研究的是,心跳和重连,虽然这次是大神写的代码,但是万变不离其宗,我们先回顾一下Netty应用心跳和重连的整个过程: 1)客户端连接服务端 2)在客户端的的ChannelPipeline中加入一个比 ...

  9. 从零开始实现简单 RPC 框架 9:网络通信之心跳与重连机制

    一.心跳 什么是心跳 在 TPC 中,客户端和服务端建立连接之后,需要定期发送数据包,来通知对方自己还在线,以确保 TPC 连接的有效性.如果一个连接长时间没有心跳,需要及时断开,否则服务端会维护很多 ...

随机推荐

  1. 51NOD 1227:平均最小公倍数——题解

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1227 懒得打公式了,看这位的吧:https://blog.csdn.ne ...

  2. 51NOD 1038:X^A Mod P——题解

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1038 X^A mod P = B,其中P为质数.给出P和A B,求< ...

  3. MYSQL性能察看

    http://fengbin2005.iteye.com/blog/1580214 网上有很多的文章教怎么配置MySQL服务器,但考虑到服务器硬件配置的不同,具体应用的差别,那些文章的做法只能作为初步 ...

  4. arp协议及简单应用

    1:什么是arp协议 参考文章:http://blog.csdn.net/tigerjibo/article/details/7351992 全称是:Address Resolution Protoc ...

  5. <audio>标签HTML5音乐播放器

    <audio>标签:用于在文档中表示音频内容.利用它,你可以在你的个人网站上放一首你喜欢的歌.    <audio src="music.mp3">< ...

  6. 双向数据绑定实现之Object.defineProperty

    vue.js利用的是es5的 defineproperty 特性实现的双向数据绑定,了解一下基本原理. 举例 var person= {}; Object.defineProperty(person, ...

  7. [LeetCode] 15. 3Sum ☆☆

    Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all un ...

  8. SpringMVC+MyBatis 返回时间格式转换的解决方案

    Spring MVC 4.X ResponseBody 日期类型Json 处理 摘自http://tramp-zzy.iteye.com/blog/2090330  2014-07-10 方法一:全局 ...

  9. js for等循环 跳出多层循环

    js for 循环 跳出多层循环 ,,,,,,,]; // 8个数 ,,,,,,,]; //8个数 testFor(); console.log(') function testFor() { ;k& ...

  10. Spring 学习笔记之整合Hibernate

    Spring和Hibernate处于不同的层次,Spring关心的是业务逻辑之间的组合关系,Spring提供了对他们的强大的管理能力, 而Hibernate完成了OR的映射,使开发人员不用再去关心SQ ...