博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何优雅地进行方法重试
阅读量:6040 次
发布时间:2019-06-20

本文共 3736 字,大约阅读时间需要 12 分钟。

程序调用第三方接口可能会出现网络抖动、超时等异常情况,这时我们通常会想到当是重试。我们首先模拟一段业务逻辑,然后开始我们重试代码当编写

/**     * 这个是需要执行的业务逻辑      * 定义了一个随机数,当低于阈值的时候,抛出异常      * 调用方catch住异常后进行重试     */    private void doSomething() {        log.info("开始业务逻辑...");        int random = RandomUtils.nextInt(100);        log.info("随机数为:{}", random);        if (random < 90) {            log.info("随机数低于阈值,准备重试");            throw new ServiceException("业务异常");        }        log.info("结束业务逻辑...");    }复制代码

1. 普通重试

最普通的重试逻辑,就是在调用方捕获到异常后,再次调用业务逻辑方法(递归),直到成功。该方案简单粗暴

public void normal(int count) {        if (count < 5) {            count += 1;            try {                doSomething();            } catch (Exception e) {                //此处可以定时休眠一点时间再次重试                try {                    TimeUnit.SECONDS.sleep(1);                } catch (InterruptedException e1) {                    e1.printStackTrace();                }                //重试                normal(count);            }        }    }复制代码

2. SpringRetry 普通模式

Spring-retry是一个开源工具包,该工具把重试操作模板定制化,可以设置重试策略和回退策略。同时重试执行实例保证线程安全,下面给出对应的示例代码

/**     * Spring提供的Retry机制     */    public void springRetry() {        // 构建重试模板实例        RetryTemplate retryTemplate = new RetryTemplate();        // 设置重试策略,主要设置重试次数和需要捕获的异常        SimpleRetryPolicy policy = new SimpleRetryPolicy(5, Collections.singletonMap(Exception.class, true));        // 设置重试回退操作策略,主要设置重试间隔时间        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();        //初始间隔        backOffPolicy.setInitialInterval(1000);        //最大间隔        backOffPolicy.setMaxInterval(10 * 1000L);        //递增倍数(即下次间隔是上次的多少倍)        backOffPolicy.setMultiplier(2);        retryTemplate.setRetryPolicy(policy);        retryTemplate.setBackOffPolicy(backOffPolicy);        // 通过RetryCallback 重试回调实例包装正常逻辑逻辑,第一次执行和重试执行执行的都是这段逻辑        final RetryCallback
retryCallback = context -> { log.info("开始重试,重试次数为: {}", context.getRetryCount()); doSomething(); return null; }; // 通过RecoveryCallback 重试流程正常结束或者达到重试上限后的退出恢复操作实例 final RecoveryCallback
recoveryCallback = context -> { log.info("执行重试结束依然失败后的代码"); return null; }; try { // 由retryTemplate 执行execute方法开始逻辑执行 retryTemplate.execute(retryCallback, recoveryCallback); } catch (Exception e) { e.printStackTrace(); } }复制代码

3. SpringRetry 注解版本

在上面的代码基础上,Spring提供了重试操作的注解,下面给出对应的示例代码。使用该方式的时候需要注意以下两点:

(1) 需要在入口类上添加@EnableRetry

(2) @Retryable只能出现在最外层的方法,同一个类中,当某个方法调用加类该注解的方法时,重试不生效

/**     * Spring提供的Retry机制     */    @Retryable(value = ServiceException.class, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2))    public void springRetryAnnotation() {        doSomething();    }    /**     * 重试失败后调用的方法(注意,需跟重处理方法在同一个类中)     */    @Recover    public void recover(ServiceException e) {        log.info("执行重试结束依然失败后的代码");    }复制代码

4. GuavaRetry版本

SpringRetry版本只能对异常进行重试,对于自定义对数据结构不能支持,如果有这方面需求的化,可以考虑用GuavaRetry进行重试,具体示例代码如下(SpringTime默认不集成,使用时需要手动添加maven依赖)

/**     * guava提供的retry机制     */    public void guavaRetry() {        //设置重试5次,同样可以设置重试超时时间        StopStrategy stopStrategy = StopStrategies.stopAfterAttempt(5);        //设置每次重试间隔        WaitStrategy waitStrategy = WaitStrategies.exponentialWait(2, 10, TimeUnit.SECONDS);        Retryer
retryer = RetryerBuilder.
newBuilder().retryIfException().withStopStrategy(stopStrategy) .withWaitStrategy(waitStrategy).build(); try { retryer.call(() -> { doSomething(); return null; }); } catch (ExecutionException | RetryException e) { e.printStackTrace(); } }复制代码

转载地址:http://qjwex.baihongyu.com/

你可能感兴趣的文章
快速构建Windows 8风格应用29-捕获图片与视频
查看>>
OC语言Block和协议
查看>>
使用xpath时出现noDefClass的错误(找不到某个类)
查看>>
.Net规则引擎介绍 - REngine
查看>>
CSS3 transforms 3D翻开
查看>>
利用传入的Type类型来调用范型方法的解决方案
查看>>
Top命令内存占用剖析
查看>>
转 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO
查看>>
求带分数(蓝桥杯)
查看>>
Bootstrap系列 -- 11. 基础表单
查看>>
Retrofit 入门学习
查看>>
Spring Boot学习笔记
查看>>
python3存入redis是bytes
查看>>
laravel 集合接口
查看>>
C/C++二进制读写png文件
查看>>
thymleaf 常用th 标签
查看>>
RTB 广告系统
查看>>
Linux signal 那些事儿(2)【转】
查看>>
InfluxDB安装及配置
查看>>
Dynamics CRM Microsoft SQL Server 指定的数据库具有更高的版本号
查看>>