如何优雅地进行方法重试

栏目: Java · 发布时间: 6年前

内容简介:程序调用第三方接口可能会出现网络抖动、超时等异常情况,这时我们通常会想到当是重试。我们首先模拟一段业务逻辑,然后开始我们重试代码当编写最普通的重试逻辑,就是在调用方捕获到异常后,再次调用业务逻辑方法(递归),直到成功。Spring-retry是一个开源工具包,该工具把重试操作模板定制化,可以设置重试策略和回退策略。同时重试执行实例保证线程安全,下面给出对应的示例代码

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

/**
     * 这个是需要执行的业务逻辑 
     * 定义了一个随机数,当低于阈值的时候,抛出异常 
     * 调用方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<Object, Exception> retryCallback = context -> {
            log.info("开始重试,重试次数为: {}", context.getRetryCount());
            doSomething();
            return null;
        };
        // 通过RecoveryCallback 重试流程正常结束或者达到重试上限后的退出恢复操作实例
        final RecoveryCallback<Object> 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<Void> retryer = RetryerBuilder.<Void>newBuilder().retryIfException().withStopStrategy(stopStrategy)
                .withWaitStrategy(waitStrategy).build();
        try {
            retryer.call(() -> {
                doSomething();
                return null;
            });
        } catch (ExecutionException | RetryException e) {
            e.printStackTrace();
        }
    }
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Rationality for Mortals

Rationality for Mortals

Gerd Gigerenzer / Oxford University Press, USA / 2008-05-02 / USD 65.00

Gerd Gigerenzer's influential work examines the rationality of individuals not from the perspective of logic or probability, but from the point of view of adaptation to the real world of human behavio......一起来看看 《Rationality for Mortals》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码