最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java利用Guava?Retry實(shí)現(xiàn)重處理

 更新時(shí)間:2022年08月26日 09:05:54   作者:不才陳某  
guava-retrying是谷歌的Guava庫的一個(gè)小擴(kuò)展,允許為任意函數(shù)調(diào)用創(chuàng)建可配置的重試策略,比如與正常運(yùn)行時(shí)間不穩(wěn)定的遠(yuǎn)程服務(wù)對(duì)話的函數(shù)調(diào)用。本文將利用其實(shí)現(xiàn)重處理,感興趣的可以了解一下

在日常開發(fā)中,尤其是在微服務(wù)盛行的時(shí)代下,我們在調(diào)用外部接口時(shí),經(jīng)常會(huì)因?yàn)榈谌浇涌诔瑫r(shí)、限流等問題從而造成接口調(diào)用失敗,那么此時(shí)我們通常會(huì)對(duì)接口進(jìn)行重試,那么問題來了,如何重試呢?該重試幾次呢?如果要設(shè)置重試時(shí)間超過多長時(shí)間后還不成功就不重試了該怎么做呢?所幸guava-retrying為我們提供了強(qiáng)大而簡單易用的重試框架guava-retrying。

guava-retrying是谷歌的Guava庫的一個(gè)小擴(kuò)展,允許為任意函數(shù)調(diào)用創(chuàng)建可配置的重試策略,比如與正常運(yùn)行時(shí)間不穩(wěn)定的遠(yuǎn)程服務(wù)對(duì)話的函數(shù)調(diào)用。

一、pom依賴

<dependency>
      <groupId>com.github.rholder</groupId>
      <artifactId>guava-retrying</artifactId>
      <version>2.0.0</version>
    </dependency>

二、使用示例

我們可以通過RetryerBuilder來構(gòu)造一個(gè)重試器,通過RetryerBuilder可以設(shè)置什么時(shí)候需要重試(即重試時(shí)機(jī))、停止重試策略、失敗等待時(shí)間間隔策略、任務(wù)執(zhí)行時(shí)長限制策略

先看一個(gè)簡單的例子:

private int invokeCount = 0;

    public int realAction(int num) {
        invokeCount++;
        System.out.println(String.format("當(dāng)前執(zhí)行第 %d 次,num:%d", invokeCount, num));
        if (num <= 0) {
            throw new IllegalArgumentException();
        }
        return num;
    }

    @Test
    public void guavaRetryTest001() {
        Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
            // 非正數(shù)進(jìn)行重試
            .retryIfRuntimeException()
            // 偶數(shù)則進(jìn)行重試
            .retryIfResult(result -> result % 2 == 0)
            // 設(shè)置最大執(zhí)行次數(shù)3次
            .withStopStrategy(StopStrategies.stopAfterAttempt(3)).build();

        try {
            invokeCount=0;
            retryer.call(() -> realAction(0));
        } catch (Exception e) {
            System.out.println("執(zhí)行0,異常:" + e.getMessage());
        }

        try {
            invokeCount=0;
            retryer.call(() -> realAction(1));
        } catch (Exception e) {
            System.out.println("執(zhí)行1,異常:" + e.getMessage());
        }

        try {
            invokeCount=0;
            retryer.call(() -> realAction(2));
        } catch (Exception e) {
            System.out.println("執(zhí)行2,異常:" + e.getMessage());
        }
    }

輸出:

當(dāng)前執(zhí)行第 1 次,num:0
當(dāng)前執(zhí)行第 2 次,num:0
當(dāng)前執(zhí)行第 3 次,num:0
執(zhí)行0,異常:Retrying failed to complete successfully after 3 attempts.
當(dāng)前執(zhí)行第 1 次,num:1
當(dāng)前執(zhí)行第 1 次,num:2
當(dāng)前執(zhí)行第 2 次,num:2
當(dāng)前執(zhí)行第 3 次,num:2
執(zhí)行2,異常:Retrying failed to complete successfully after 3 attempts.

三、重試時(shí)機(jī)

RetryerBuilder的retryIfXXX()方法用來設(shè)置**在什么情況下進(jìn)行重試,總體上可以分為根據(jù)執(zhí)行異常進(jìn)行重試和根據(jù)方法執(zhí)行結(jié)果進(jìn)行重試兩類。關(guān)注公眾號(hào):“碼猿技術(shù)專欄”,回復(fù)關(guān)鍵詞:“1111” 獲取阿里內(nèi)部Java調(diào)優(yōu)手冊

1. 根據(jù)異常進(jìn)行重試

2. 根據(jù)返回結(jié)果進(jìn)行重試

retryIfResult(@Nonnull Predicate resultPredicate) 這個(gè)比較簡單,當(dāng)我們傳入的resultPredicate返回true時(shí)則進(jìn)行重試

四、停止重試策略StopStrategy

停止重試策略用來決定什么時(shí)候不進(jìn)行重試,其接口com.github.rholder.retry.StopStrategy,停止重試策略的實(shí)現(xiàn)類均在com.github.rholder.retry.StopStrategies中,它是一個(gè)策略工廠類。

public interface StopStrategy {

    /**
     * Returns <code>true</code> if the retryer should stop retrying.
     *
     * @param failedAttempt the previous failed {@code Attempt}
     * @return <code>true</code> if the retryer must stop, <code>false</code> otherwise
     */
    boolean shouldStop(Attempt failedAttempt);
}

1. NeverStopStrategy

此策略將永遠(yuǎn)重試,永不停止,查看其實(shí)現(xiàn)類,直接返回了false:

@Override
public boolean shouldStop(Attempt failedAttempt) {
 return false;
}

2. StopAfterAttemptStrategy

當(dāng)執(zhí)行次數(shù)到達(dá)指定次數(shù)之后停止重試,查看其實(shí)現(xiàn)類:

private static final class StopAfterAttemptStrategy implements StopStrategy {
        private final int maxAttemptNumber;

        public StopAfterAttemptStrategy(int maxAttemptNumber) {
            Preconditions.checkArgument(maxAttemptNumber >= 1, "maxAttemptNumber must be >= 1 but is %d", maxAttemptNumber);
            this.maxAttemptNumber = maxAttemptNumber;
        }

        @Override
        public boolean shouldStop(Attempt failedAttempt) {
            return failedAttempt.getAttemptNumber() >= maxAttemptNumber;
        }
    }

3. StopAfterDelayStrategy

當(dāng)距離方法的第一次執(zhí)行超出了指定的delay時(shí)間時(shí)停止,也就是說一直進(jìn)行重試,當(dāng)進(jìn)行下一次重試的時(shí)候會(huì)判斷從第一次執(zhí)行到現(xiàn)在的所消耗的時(shí)間是否超過了這里指定的delay時(shí)間,查看其實(shí)現(xiàn):

private static final class StopAfterAttemptStrategy implements StopStrategy {
        private final int maxAttemptNumber;

        public StopAfterAttemptStrategy(int maxAttemptNumber) {
            Preconditions.checkArgument(maxAttemptNumber >= 1, "maxAttemptNumber must be >= 1 but is %d", maxAttemptNumber);
            this.maxAttemptNumber = maxAttemptNumber;
        }

        @Override
        public boolean shouldStop(Attempt failedAttempt) {
            return failedAttempt.getAttemptNumber() >= maxAttemptNumber;
        }
    }

五、重試間隔策略、重試阻塞策略

這兩個(gè)策略放在一起說,它們合起來的作用就是用來控制重試任務(wù)之間的間隔時(shí)間,以及如何任務(wù)在等待時(shí)間間隔時(shí)如何阻塞。也就是說WaitStrategy決定了重試任務(wù)等待多久后進(jìn)行下一次任務(wù)的執(zhí)行,BlockStrategy用來決定任務(wù)如何等待。它們兩的策略工廠分別為com.github.rholder.retry.WaitStrategies和BlockStrategies。

1.BlockStrategy

(1) ThreadSleepStrategy

這個(gè)是BlockStrategies,決定如何阻塞任務(wù),其主要就是通過**Thread.sleep()**來進(jìn)行阻塞的,查看其實(shí)現(xiàn):

@Immutable
    private static class ThreadSleepStrategy implements BlockStrategy {

        @Override
        public void block(long sleepTime) throws InterruptedException {
            Thread.sleep(sleepTime);
        }
    }

2. WaitStrategy

(1) IncrementingWaitStrategy

該策略在決定任務(wù)間隔時(shí)間時(shí),返回的是一個(gè)遞增的間隔時(shí)間,即每次任務(wù)重試間隔時(shí)間逐步遞增,越來越長,查看其實(shí)現(xiàn):

private static final class IncrementingWaitStrategy implements WaitStrategy {
        private final long initialSleepTime;
        private final long increment;

        public IncrementingWaitStrategy(long initialSleepTime,
                                        long increment) {
            Preconditions.checkArgument(initialSleepTime >= 0L, "initialSleepTime must be >= 0 but is %d", initialSleepTime);
            this.initialSleepTime = initialSleepTime;
            this.increment = increment;
        }

        @Override
        public long computeSleepTime(Attempt failedAttempt) {
            long result = initialSleepTime + (increment * (failedAttempt.getAttemptNumber() - 1));
            return result >= 0L ? result : 0L;
        }
    }

該策略輸入一個(gè)起始間隔時(shí)間值和一個(gè)遞增步長,然后每次等待的時(shí)長都遞增increment時(shí)長。

(2) RandomWaitStrategy

顧名思義,返回一個(gè)隨機(jī)的間隔時(shí)長,我們需要傳入的就是一個(gè)最小間隔和最大間隔,然后隨機(jī)返回介于兩者之間的一個(gè)間隔時(shí)長,其實(shí)現(xiàn)為:

private static final class RandomWaitStrategy implements WaitStrategy {
        private static final Random RANDOM = new Random();
        private final long minimum;
        private final long maximum;

        public RandomWaitStrategy(long minimum, long maximum) {
            Preconditions.checkArgument(minimum >= 0, "minimum must be >= 0 but is %d", minimum);
            Preconditions.checkArgument(maximum > minimum, "maximum must be > minimum but maximum is %d and minimum is", maximum, minimum);

            this.minimum = minimum;
            this.maximum = maximum;
        }

        @Override
        public long computeSleepTime(Attempt failedAttempt) {
            long t = Math.abs(RANDOM.nextLong()) % (maximum - minimum);
            return t + minimum;
        }
    }

(3) FixedWaitStrategy

該策略是返回一個(gè)固定時(shí)長的重試間隔。查看其實(shí)現(xiàn):

private static final class FixedWaitStrategy implements WaitStrategy {
        private final long sleepTime;

        public FixedWaitStrategy(long sleepTime) {
            Preconditions.checkArgument(sleepTime >= 0L, "sleepTime must be >= 0 but is %d", sleepTime);
            this.sleepTime = sleepTime;
        }

        @Override
        public long computeSleepTime(Attempt failedAttempt) {
            return sleepTime;
        }
    }

() ExceptionWaitStrategy

該策略是由方法執(zhí)行異常來決定是否重試任務(wù)之間進(jìn)行間隔等待,以及間隔多久。

private static final class ExceptionWaitStrategy<T extends Throwable> implements WaitStrategy {
        private final Class<T> exceptionClass;
        private final Function<T, Long> function;

        public ExceptionWaitStrategy(@Nonnull Class<T> exceptionClass, @Nonnull Function<T, Long> function) {
            this.exceptionClass = exceptionClass;
            this.function = function;
        }

        @SuppressWarnings({"ThrowableResultOfMethodCallIgnored", "ConstantConditions", "unchecked"})
        @Override
        public long computeSleepTime(Attempt lastAttempt) {
            if (lastAttempt.hasException()) {
                Throwable cause = lastAttempt.getExceptionCause();
                if (exceptionClass.isAssignableFrom(cause.getClass())) {
                    return function.apply((T) cause);
                }
            }
            return 0L;
        }
    }

(5) CompositeWaitStrategy

這個(gè)沒啥好說的,顧名思義,就是一個(gè)策略的組合,你可以傳入多個(gè)WaitStrategy,然后所有WaitStrategy返回的間隔時(shí)長相加就是最終的間隔時(shí)間。查看其實(shí)現(xiàn):

private static final class CompositeWaitStrategy implements WaitStrategy {
        private final List<WaitStrategy> waitStrategies;

        public CompositeWaitStrategy(List<WaitStrategy> waitStrategies) {
            Preconditions.checkState(!waitStrategies.isEmpty(), "Need at least one wait strategy");
            this.waitStrategies = waitStrategies;
        }

        @Override
        public long computeSleepTime(Attempt failedAttempt) {
            long waitTime = 0L;
            for (WaitStrategy waitStrategy : waitStrategies) {
                waitTime += waitStrategy.computeSleepTime(failedAttempt);
            }
            return waitTime;
        }
    }

(6) FibonacciWaitStrategy

這個(gè)策略與IncrementingWaitStrategy有點(diǎn)相似,間隔時(shí)間都是隨著重試次數(shù)的增加而遞增的,不同的是,F(xiàn)ibonacciWaitStrategy是按照斐波那契數(shù)列來進(jìn)行計(jì)算的,使用這個(gè)策略時(shí),我們需要傳入一個(gè)乘數(shù)因子和最大間隔時(shí)長,其實(shí)現(xiàn)就不貼了

(7) ExponentialWaitStrategy

這個(gè)與IncrementingWaitStrategy、FibonacciWaitStrategy也類似,間隔時(shí)間都是隨著重試次數(shù)的增加而遞增的,但是該策略的遞增是呈指數(shù)級(jí)遞增。查看其實(shí)現(xiàn):

private static final class ExponentialWaitStrategy implements WaitStrategy {
        private final long multiplier;
        private final long maximumWait;

        public ExponentialWaitStrategy(long multiplier,
                                       long maximumWait) {
            Preconditions.checkArgument(multiplier > 0L, "multiplier must be > 0 but is %d", multiplier);
            Preconditions.checkArgument(maximumWait >= 0L, "maximumWait must be >= 0 but is %d", maximumWait);
            Preconditions.checkArgument(multiplier < maximumWait, "multiplier must be < maximumWait but is %d", multiplier);
            this.multiplier = multiplier;
            this.maximumWait = maximumWait;
        }

        @Override
        public long computeSleepTime(Attempt failedAttempt) {
            double exp = Math.pow(2, failedAttempt.getAttemptNumber());
            long result = Math.round(multiplier * exp);
            if (result > maximumWait) {
                result = maximumWait;
            }
            return result >= 0L ? result : 0L;
        }
    }

六、重試監(jiān)聽器RetryListener

當(dāng)發(fā)生重試時(shí),將會(huì)調(diào)用RetryListener的onRetry方法,此時(shí)我們可以進(jìn)行比如記錄日志等額外操作。

public int realAction(int num) {
        if (num <= 0) {
            throw new IllegalArgumentException();
        }
        return num;
    }

    @Test
    public void guavaRetryTest001() throws ExecutionException, RetryException {
        Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder().retryIfException()
            .withRetryListener(new MyRetryListener())
            // 設(shè)置最大執(zhí)行次數(shù)3次
            .withStopStrategy(StopStrategies.stopAfterAttempt(3)).build();
        retryer.call(() -> realAction(0));

    }

    private static class MyRetryListener implements RetryListener {

        @Override
        public <V> void onRetry(Attempt<V> attempt) {
            System.out.println("第" + attempt.getAttemptNumber() + "次執(zhí)行");
        }
    }

輸出:

第1次執(zhí)行
第2次執(zhí)行
第3次執(zhí)行

七、重試原理

其實(shí)到這一步之后,實(shí)現(xiàn)原理大概就很清楚了,就是由上述各種策略配合從而達(dá)到了非常靈活的重試機(jī)制。在這之前我們看一個(gè)上面沒說的東東-Attempt:

public interface Attempt<V> {
    public V get() throws ExecutionException;

    public boolean hasResult();
    
    public boolean hasException();

    public V getResult() throws IllegalStateException;

    public Throwable getExceptionCause() throws IllegalStateException;

    public long getAttemptNumber();

    public long getDelaySinceFirstAttempt();
}

通過接口方法可以知道Attempt這個(gè)類包含了任務(wù)執(zhí)行次數(shù)、任務(wù)執(zhí)行異常、任務(wù)執(zhí)行結(jié)果、以及首次執(zhí)行任務(wù)至今的時(shí)間間隔,那么我們后續(xù)的不管重試時(shí)機(jī)、還是其他策略都是根據(jù)此值來決定。

接下來看關(guān)鍵執(zhí)行入口Retryer##call:

public V call(Callable<V> callable) throws ExecutionException, RetryException {
        long startTime = System.nanoTime();
        
        // 執(zhí)行次數(shù)從1開始
        for (int attemptNumber = 1; ; attemptNumber++) {
            Attempt<V> attempt;
            try {
                // 嘗試執(zhí)行
                V result = attemptTimeLimiter.call(callable);
                
                // 執(zhí)行成功則將結(jié)果封裝為ResultAttempt
                attempt = new Retryer.ResultAttempt<V>(result, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
            } catch (Throwable t) {
                // 執(zhí)行異常則將結(jié)果封裝為ExceptionAttempt
                attempt = new Retryer.ExceptionAttempt<V>(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
            }

            // 這里將執(zhí)行結(jié)果傳給RetryListener做一些額外事情
            for (RetryListener listener : listeners) {
                listener.onRetry(attempt);
            }

            // 這個(gè)就是決定是否要進(jìn)行重試的地方,如果不進(jìn)行重試直接返回結(jié)果,執(zhí)行成功就返回結(jié)果,執(zhí)行失敗就返回異常
            if (!rejectionPredicate.apply(attempt)) {
                return attempt.get();
            }
            
            // 到這里,說明需要進(jìn)行重試,則此時(shí)先決定是否到達(dá)了停止重試的時(shí)機(jī),如果到達(dá)了則直接返回異常
            if (stopStrategy.shouldStop(attempt)) {
                throw new RetryException(attemptNumber, attempt);
            } else {
                // 決定重試時(shí)間間隔
                long sleepTime = waitStrategy.computeSleepTime(attempt);
                try {
                    // 進(jìn)行阻塞
                    blockStrategy.block(sleepTime);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RetryException(attemptNumber, attempt);
                }
            }
        }

八、總結(jié)

通篇下來可以看到其實(shí)核心實(shí)現(xiàn)并不難,但是此框架通過建造者模式和策略模式組合運(yùn)用,提供了十分清晰明了且靈活的重試機(jī)制,其設(shè)計(jì)思路還是值得借鑒學(xué)習(xí)!

以上就是Java利用Guava Retry實(shí)現(xiàn)重處理的詳細(xì)內(nèi)容,更多關(guān)于Java Guava Retry的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • IDEA提示 add *** to custom tags問題及解決

    IDEA提示 add *** to custom tags問題及解決

    文章介紹了如何在文檔注釋中添加自定義注解(@xxx),并提供了添加和刪除注解的方法,總結(jié)了個(gè)人經(jīng)驗(yàn),希望對(duì)大家有所幫助
    2024-12-12
  • 解決java.util.HashMap$Values?cannot?be?cast?to?java.ut的問題

    解決java.util.HashMap$Values?cannot?be?cast?to?java.ut的問題

    這篇文章主要介紹了解決java.util.HashMap$Values?cannot?be?cast?to?java.ut的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 挑戰(zhàn)4道Java試題

    挑戰(zhàn)4道Java試題

    這篇文章主要為大家分享了4道Java基礎(chǔ)題,幫助大家鞏固基礎(chǔ)知識(shí),夯實(shí)java基礎(chǔ)技能,感興趣的朋友快點(diǎn)挑戰(zhàn)
    2015-12-12
  • Java中的forEach循環(huán)詳細(xì)解讀

    Java中的forEach循環(huán)詳細(xì)解讀

    這篇文章主要介紹了Java中的forEach循環(huán)詳細(xì)解讀,不要再foreach循環(huán)里面進(jìn)行元素的add和remove,如果你非要進(jìn)行remove元素,那么請(qǐng)使用Iterator方式,如果存在并發(fā),那么你一定要選擇加鎖,需要的朋友可以參考下
    2023-12-12
  • Spring Junit單元測試加載配置文件失敗問題

    Spring Junit單元測試加載配置文件失敗問題

    這篇文章主要介紹了Spring Junit加載配置文件失敗問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • java高并發(fā)的ReentrantLock重入鎖

    java高并發(fā)的ReentrantLock重入鎖

    這篇文章主要介紹了如何教你完全理解ReentrantLock重入鎖,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面我們來一起學(xué)習(xí)一下吧
    2021-10-10
  • 深入解析Java編程中final關(guān)鍵字的使用

    深入解析Java編程中final關(guān)鍵字的使用

    這篇文章主要介紹了Java編程中final關(guān)鍵字的使用,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2016-01-01
  • Java新特性之Nashorn_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java新特性之Nashorn_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了Java新特性之Nashorn的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • Java排序之冒泡排序的實(shí)現(xiàn)與優(yōu)化

    Java排序之冒泡排序的實(shí)現(xiàn)與優(yōu)化

    冒泡排序是一種簡單的交換排序。之所以叫做冒泡排序,因?yàn)槲覀兛梢园衙總€(gè)元素當(dāng)成一個(gè)小氣泡,根據(jù)氣泡大小,一步一步移動(dòng)到隊(duì)伍的一端,最后形成一定對(duì)的順序。本文將利用Java實(shí)現(xiàn)冒泡排序,并進(jìn)行一定的優(yōu)化,希望對(duì)大家有所幫助
    2022-11-11
  • Kotlin 基礎(chǔ)語法實(shí)例詳解

    Kotlin 基礎(chǔ)語法實(shí)例詳解

    這篇文章主要介紹了Kotlin 基礎(chǔ)語法實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06

最新評(píng)論

惠水县| 东乡族自治县| 芜湖县| 栖霞市| 清丰县| 揭西县| 沽源县| 天镇县| 灯塔市| 万全县| 临夏市| 绥芬河市| 寻乌县| 桦川县| 大连市| 中阳县| 涞水县| 合阳县| 筠连县| 含山县| 长海县| 个旧市| 太和县| 富川| 都兰县| 巫溪县| 蒙城县| 新竹县| 平邑县| 洮南市| 丹东市| 萨嘎县| 资阳市| 鄂托克前旗| 蒲城县| 夏津县| 江口县| 文水县| 枣庄市| 宜君县| 晋中市|