guava-retrying 源码解析(等待策略详解)

一、等待策略相关类:

1、等待策略接口:WaitStrategy接口

该接口只有一个方法,就是返回尝试失败之后,下一次尝试之前的等待时间。
long computeSleepTime(Attempt failedAttempt); 

2、创建等待策略对象的工厂类:com.github.rholder.retry.WaitStrategies类,这是一个常量类,负责创建等待策略对象。

  在该工厂类的内部实现了七种等待策略,如下:

  guava-retrying 源码解析(等待策略详解)

二、七种等待策略详解如下:

1、等待固定时间的策略:FixedWaitStrategy类 (默认策略,等待时间为0L)

  这个类很简单,方法抛出常后,隔固定时间进行一次重试即可。

  // 方法抛出异常后,conputeSleepTime返回固定的时间,单位ms
  @Override   public long computeSleepTime(Attempt failedAttempt) {   return sleepTime;   }

2、等待时间自增的策略:IncrementingWaitStrategy类

  这个类每次重试的间隔时间随着重试次数的增加而增加,每次增加固定的时间。

   // initialSleepTime 默认时间
// increment 自增时间
// getAttemptNumber 第几次重试
    @Override
    public long computeSleepTime(Attempt failedAttempt) {
        long result = initialSleepTime + (increment * (failedAttempt.getAttemptNumber() - 1));
        return result >= 0L ? result : 0L;
    }    

3、等待时间随机的策略:RandomWaitStrategy类

  这种策略等待时间在某个范围:

    如果传入一个参数,则为 [0L,timeUnit.toMillis(maximumTime)];

    如果传入两个个参数,则为 [minimumTimeUnit.toMillis(minimumTime),maximumTimeUnit.toMillis(maximumTime)]

  guava-retrying 源码解析(等待策略详解)

4、等待时间指数形式增长:ExponentialWaitStrategy类

  这中策略等待时间呈指数形式增长,指数形式增长,如果指定最大等待时间,则增长到最大等待时间就不再增长;如果没有指定最大等待时间,则最大等待时间为Long.MAX_VALUE

  主要逻辑如下:

  guava-retrying 源码解析(等待策略详解)

5、等待时间以斐波拉契数列形式增长:FibonacciWaitStrategy类

  有三个工厂方法:

    无参:等待时间从 1 增长到 Long.MAX_VALUE

    两个参数:等待时间从 1 增长到 maximumTimeUnit.toMillis(maximumTime),到最大值以后等待时间恒定不变

    三个参数:等待时间从 multiplier 增长到 maximumTimeUnit.toMillis(maximumTime)

  等待时间增长主要实现逻辑:

  guava-retrying 源码解析(等待策略详解)

6、如果抛出的是指定异常,则从传入的函数中取得等待时间:ExceptionWaitStrategy类

  如果抛出的是指定异常,则从传入的function中取得等待时间并返回。如果异常不匹配,则返回等待时间为0L。

  具体实现逻辑如下: 

    其中lastAttempt.getExceptionCause() 为抛出的异常;exceptionClass为指定异常。

        guava-retrying 源码解析(等待策略详解)

  这里简单解释一下 Class.isAssignableFrom(Class clazz) 方法:该方法用来判断一个类Class1和另一个类Class2是否相同或者 Class1是Class2的父类或接口。     

 1 interface DemoInterface { }
 2 
 3 class DemoParent { }
 4 
 5 public class Demo extends DemoParent implements DemoInterface{
 6 
 7     public static void main(String[] args) {
 8 
 9         System.out.println(Demo.class.isAssignableFrom(DemoParent.class));    // false
10         System.out.println(Demo.class.isAssignableFrom(DemoInterface.class));   // false
11 
12         System.out.println(DemoParent.class.isAssignableFrom(Demo.class));   // true
13         System.out.println(DemoInterface.class.isAssignableFrom(Demo.class));    // true
14 
15         System.out.println(Demo.class.isAssignableFrom(Demo.class));    // true
16     }
17 }

7、组合多种等待策略,得到等待时间的方式:CompositeWaitStrategy类

   在获取等待时间时会获取多种等待策略各自的等待时间,然后累加这些等待时间并返回。

 /**
     * 组合等待策略
     * @author yjp
     */
    @Test
    public void testCompositeWaitStrategy() {
        WaitStrategy fibonacciWait = WaitStrategies.fibonacciWait(1000L, 50000L, TimeUnit.MILLISECONDS);
        WaitStrategy fixedWait = WaitStrategies.fixedWait(1000L, TimeUnit.MILLISECONDS);
        WaitStrategy compositeWait = WaitStrategies.join(fibonacciWait, fixedWait);
        assertEquals(2000L, compositeWait.computeSleepTime(failedAttempt(1, 1)));
        // 第5次斐波拉契增长的等待时间是 5000L, 加上固定的等待时间 1000L
        assertEquals(6000L, compositeWait.computeSleepTime(failedAttempt(5, 1)));
    }
  
// --------------源码具体实现----------------
@Override
public long computeSleepTime(Attempt failedAttempt) {
long waitTime = 0L;
for (WaitStrategy waitStrategy : waitStrategies) {
     // 各策略根据各自的逻辑获取自己的等待是时间。然后累加到result中
waitTime += waitStrategy.computeSleepTime(failedAttempt);
}
return waitTime;
}