zoukankan      html  css  js  c++  java
  • 学习使用Guava Retryer

    目录

      一、引入

      二、快速上手

        2.1、导入依赖

        2.2、第一个示例

      三、重试设置

        3.1、重试条件设置

        3.2、重试次数设置

        3.3、重试间隔设置

    一、引入

      在平时的开发工作中,重试机制,是一个很重要的逻辑,比如调用其他服务时,如果出现超时,那么可以等100毫秒后再进行调用,或者出现异常时,需要重试;可以重试多次,也可以重试1次,这个都是可以在程序中设定的。

      实现上面的逻辑,最简单的方式就是使用for循环了,示例如下:

    package cn.ganlixin.guava;
    
    import org.junit.Test;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class UseRetryer {
    
        private static final Logger log = LoggerFactory.getLogger(UseRetryer.class);
    
        @Test
        public void testUseFor() throws InterruptedException {
            int retryTimes = 3;  // 重试次数
    
            // 使用for循环控制重试
            for (int i = 0; i < retryTimes; i++) {
    
                try {
                    // 逻辑代码,比如调用其他服务的接口
    
                } catch (Exception e) {
                    log.warn("第{}次运行出现异常,", i);
                    // 如果出现异常,休眠100毫秒后重试(继续for循环)
                    Thread.sleep(100);
                    continue;
                }
    
                // 执行成功,立即终止for循环。
                break;
            }
    
        }
    }
    

      上面的代码,实现起来很简单,也很好理解,我之前也是这样做的。但是这样做,其实是有一个弊端的,因为业务逻辑代码,和一些控制操作(什么时候重试、隔多久重试)是写在一块的,比较乱。

      本文所讲的Guava Retryer可以解决上面的问题(还有其他优点)。  

    二、快速上手

    2.1、导入依赖

      Guava Retryer并不属于Guava,他是一个基于Guava,提供重试机制的库。

      guava retryer的github网址:https://github.com/rholder/guava-retrying,包含有使用文档。

    <dependency>
    	<groupId>com.google.guava</groupId>
    	<artifactId>guava</artifactId>
    	<version>28.0-jre</version>
    </dependency>
    
    <dependency>
    	<groupId>com.github.rholder</groupId>
    	<artifactId>guava-retrying</artifactId>
    	<version>2.0.0</version>
    	<!-- 排除与guava重复的依赖 -->
    	<exclusions>
    		<exclusion>
    			<groupId>com.google.guava</groupId>
    			<artifactId>guava</artifactId>
    		</exclusion>
    		<exclusion>
    			<groupId>com.google.code.findbugs</groupId>
    			<artifactId>jsr305</artifactId>
    		</exclusion>
    	</exclusions>
    </dependency>
    

      

    2.2、第一个示例

      先提及一下, retryer是一个重试器,可以对重试器进行设置,比如什么情况下重试、隔多久重试、重试多少次...

      创建好重试器后,就可以使用重试器来进行执行指定的操作(实际的业务逻辑):

    package cn.ganlixin.guava;
    
    import com.github.rholder.retry.*;
    import org.junit.Test;
    
    import java.time.LocalTime;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.TimeUnit;
    
    public class UseRetryer {
    
        // 需要重试执行的操作
        private Boolean testCode() {
            System.out.println(LocalTime.now());
    
            // 强制抛出异常,触发重试
            if (true) {
                throw new RuntimeException("手动测试抛出异常");
            } else {
                return false;
            }
        }
    
        @Test
        public void testFirstRetryer() throws ExecutionException, RetryException, InterruptedException {
            // 创建一个重试器,重试器执行的方法,返回值为Boolean类型
            Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
                    // 出现异常时,会重试
                    .retryIfException()
                    // 失败后,隔2秒后重试
                    .withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
                    // 重试3次后,仍未成功,就不再重试
                    .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                    .build();
    
            // 使用重试器,执行具体逻辑
            Boolean res = retryer.call(() -> {
                return testCode();
            });
        }
    }
    

      

      运行程序,输出:

    23:35:37.753
    23:35:39.754
    23:35:41.759
    
    com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 3 attempts.
    ..........
    Caused by: java.lang.RuntimeException: 手动测试抛出异常
    ..........
    

      

    三、重试设置

      上面简单介绍了怎么使用guava retryer,但是并没有看出retryer的优点,下面对guava retryer的重试设置进行介绍,比如,什么时候重试,重试多少次,每次充重试间隔多久..然后就可以发现guava retryer在进行重试时,挺“优雅”的。

    3.1、重试条件设置

      什么时候执行重试,Guava Retryer有多个匹配方法:

    package cn.ganlixin.guava;
    
    import com.github.rholder.retry.RetryException;
    import com.github.rholder.retry.Retryer;
    import com.github.rholder.retry.RetryerBuilder;
    import com.github.rholder.retry.StopStrategies;
    import org.apache.commons.lang3.StringUtils;
    import org.junit.Test;
    
    import java.util.concurrent.ExecutionException;
    
    public class UseRetryer {
    
        @Test
        public void testWhenRetry() throws ExecutionException, RetryException {
            final Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
                    // 当运行结果大于10的时候,需要重试(表达式返回true,则重试)
                    .retryIfResult(res -> {
                        return res > 10;
                    })
    
                    // 当抛出异常时,就会进行重试
                    .retryIfException()
    
                    // 或者当抛出ArithmeticException异常时,进行重试
                    .retryIfExceptionOfType(ArithmeticException.class)
    
                    // 如果抛出RuntimeException异常时,进行重试
                    .retryIfRuntimeException()
    
                    // 捕获到异常,对异常进行处理,返回true时,会进行重试
                    .retryIfException(exception -> {
                        System.out.println("捕获到" + exception);
                        // 可以对异常信息、异常种类进行处理,决定是否需要重试
                        return StringUtils.contains(exception.getMessage(), "wrong");
                    })
    
                    // 重试3次
                    .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                    .build();
    
            Integer res = retryer.call(() -> {
                throw new Exception();
            });
    
            System.out.println(res);
        }
    }

      

    3.2、重试次数设置

      前面说了什么情况下需要重试,那么需要重试多少次呢?

      guava retryer中,如果没有设置重试多少次,那么将会没有休止地一直重试(死循环),所以建议一定要设置重试次数。

    package cn.ganlixin.guava;
    
    import com.github.rholder.retry.Retryer;
    import com.github.rholder.retry.RetryerBuilder;
    import com.github.rholder.retry.StopStrategies;
    import org.junit.Test;
    
    public class UseRetryer {
    
        @Test
        public void testRetryStop() {
            Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
                    // 抛出异常时重试
                    .retryIfException()
                    // 设置什么时候停止重试
                    // 这里设置的是,执行3次都失败了就停止重试
                    .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                    .build();
        }
    }
    

      设置停止策略,主要是使用StopStrategies类的静态方法,如下:

    // 不停止,一直重试(默认)
    StopStrategies.neverStop()
    
    // attemptNumber次失败后,停止重试
    StopStrategies.stopAfterAttempt(int attemptNumber)
    
    // 执行多久后停止(在未到停止的时间节点前,如果失败,会一致重试)
    StopStrategies.stopAfterDelay(2, TimeUnit.SECONDS)
    

      

    3.3、重试间隔设置

      重试时间间隔设置,是指当执行失败后,执行下一次重试,需要等多久,这就是重试间隔策略。

      下面是一个简单示例:

    package cn.ganlixin.guava;
    
    import com.github.rholder.retry.Retryer;
    import com.github.rholder.retry.RetryerBuilder;
    import com.github.rholder.retry.WaitStrategies;
    import org.junit.Test;
    
    import java.util.concurrent.TimeUnit;
    
    public class UseRetryer {
    
        @Test
        public void testRetryInteval() {
            Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
                    // 出现异常时重试
                    .retryIfException()
                    // 设置重试时间间隔,此处设置固定时间间隔(2秒)
                    .withWaitStrategy(WaitStrategies.fixedWait(2, TimeUnit.SECONDS))
                    .build();
        }
    }
    

      和重试次数类似,重试间隔,主要使用WaitStrategies类的静态方法进行设置(有很多方法),常用的如下:

    // 失败后没有间隔,立即重试(默认)
    WaitStrategies.noWait()
    
    // 固定时间间隔(3秒)
    WaitStrategies.fixedWait(3, TimeUnit.SECONDS)
    
    // 设置第一次重试的时间间隔,然后后面每次重试时间间隔的增量
    incrementingWait(long initialSleepTime, TimeUnit initialSleepTimeUnit, long increment, TimeUnit incrementTimeUnit) 
    WaitStrategies.incrementingWait(2, TimeUnit.SECONDS, 1, TimeUnit.SECONDS)
    // 解释:第一次重试间隔2秒,后面每次间隔时间是在前一个间隔上加1秒(就是3秒),再下一次是4秒
    

      

      

  • 相关阅读:
    16、springboot——错误处理原理+定制错误页面(1)
    15、springboot——CRUD-跳转到修改员工页面+员工修改和删除实现 ⑥
    14、springboot——CRUD-跳转到添加员工页面+员工添加实现⑤
    13、springboot——CRUD-thymeleaf公共页面元素抽取④
    12、springboot——CRUD登录和拦截③
    11、springboot——CRUD国际化②
    10、springboot——CRUD导入静态资源以及设置默认访问首页①
    9、springmvc的自动配置
    8、模板引擎thymeleaf(百里香叶)
    7、对静态资源映射的规则
  • 原文地址:https://www.cnblogs.com/-beyond/p/12275842.html
Copyright © 2011-2022 走看看