【Spring】RetryTemplate

1.基本概念

1.1應(yīng)用場景

1.1.1 數(shù)據(jù)同步

有時候項目需要進(jìn)行同步數(shù)據(jù)(定時任務(wù)),一定要同步成功,不然對于業(yè)務(wù)會有影響锦积,偶發(fā)性的會出現(xiàn)調(diào)用接口失敗,失敗并不是特別多东羹,一般的流程如下:
(1)循環(huán)的進(jìn)行遠(yuǎn)程調(diào)用番电,同步數(shù)據(jù)容达,記錄一下調(diào)用失敗的記錄
(2)休眠一段時間构舟,繼續(xù)循環(huán)調(diào)用失敗的記錄
(3)如果再調(diào)用失敗洪碳、通過人工二次調(diào)用進(jìn)行修復(fù)

1.1.2 拋出xxx異诚廖眨或者返回結(jié)果為x 需要重試

比如:遠(yuǎn)程調(diào)用超時闪金、網(wǎng)絡(luò)突然中斷等可以重試

1.2 重試框架需要解決的問題

1.2.1 重試的策略(RetryPolicy)

無限重試?最多重試幾次论颅、指定的時間范圍內(nèi)可以重試哎垦、或者多種重試策略組合。

1.2.2 重試的要休眠多久(BackOffPolicy)

重試時間間隔恃疯,每次都休眠固定的時間撼泛、第一次1s 第二次2s 第三次4s 、隨機(jī)的休眠時間

1.2.3兜底方案(Recover)

如果所有的重試都失敗了澡谭、兜底方案是什么愿题?有點類似限流,最差返回你系統(tǒng)繁忙的界面。

2.spring retry

Spring Retry 是從 Spring batch 中獨立出來的一個功能蛙奖,主要實現(xiàn)了重試和熔斷潘酗,對于那些重試后不會改變結(jié)果,毫無意義的操作雁仲,不建議使用重試仔夺。spring retry提供了注解和編程 兩種支持,提供了 RetryTemplate 支持攒砖,類似RestTemplate缸兔。整個流程如下:


image.png

具體使用過程中涉及的核心對象有:
RetryTemplate: 封裝了Retry基本操作日裙,是進(jìn)入spring-retry框架的整體流程入口,通過RetryTemplate可以指定監(jiān)聽、回退策略惰蜜、重試策略等昂拂。
RetryCallback:該接口封裝了業(yè)務(wù)代碼,且failback后抛猖,會再次調(diào)用RetryCallback接口
RetryPolicy:重試策略格侯,描述將以什么樣的方式調(diào)用RetryCallback接口
BackOffPolicy :回退策略,當(dāng)出現(xiàn)錯誤時延遲多少時間繼續(xù)調(diào)用

2.1 添加依賴

        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
            <version>1.1.5.RELEASE</version>
        </dependency>

2.2 使用步驟

(1)定義重試策略RetryPolicy
實際過程如果不定義财著,則默認(rèn)SimpleRetryPolicy策略(重試3次)联四。重試策略有以下種:
NeverRetryPolicy:只允許調(diào)用RetryCallback一次,不允許重試撑教;
AlwaysRetryPolicy:允許無限重試朝墩,直到成功,此方式邏輯不當(dāng)會導(dǎo)致死循環(huán)伟姐;
SimpleRetryPolicy:固定次數(shù)重試策略鱼辙,默認(rèn)重試最大次數(shù)為3次,RetryTemplate默認(rèn)使用的策略玫镐;
TimeoutRetryPolicy:超時時間重試策略,默認(rèn)超時時間為1秒怠噪,在指定的超時時間內(nèi)允許重試恐似;
CircuitBreakerRetryPolicy:有熔斷功能的重試策略,需設(shè)置3個參數(shù)openTimeout傍念、resetTimeout和delegate矫夷;
CompositeRetryPolicy:組合重試策略,有兩種組合方式憋槐,樂觀組合重試策略是指只要有一個策略允許重試即

// 重試策略,指定重試5次
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(5);
retryTemplate.setRetryPolicy(retryPolicy);

配置之后在RetryTemplate中指定
(2)定義退避策略(BackOffPolicy )
策略主要有以下幾種:
FixedBackOffPolicy 固定時間
ExponentialBackOffPolicy 指數(shù)退避策略
ExponentialRandomBackOffPolicy 指數(shù)隨機(jī)退避策略

        RetryTemplate retryTemplate = new RetryTemplate();
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(3000);
        backOffPolicy.setMultiplier(2);
        backOffPolicy.setMaxInterval(15000);
        retryTemplate.setBackOffPolicy(backOffPolicy);

配置之后在RetryTemplate中指定
(3)RetryTemplate執(zhí)行整體流程
RetryTemplate中指定回退策略為ExponentialBackOffPolicy双藕,指定重試策略為SimpleRetryPolicy,執(zhí)行操作使用(RetryCallback 執(zhí)行業(yè)務(wù)邏輯 ,RecoveryCallback 兜底)阳仔。這里面需要用到以下核心對象
RetryCallback :業(yè)務(wù)回調(diào)入口忧陪,為retryTemplate.execute時執(zhí)行的回調(diào)
RecoveryCallback :兜底回調(diào)入口
RetryContext 重試上下文

//execute接受兩個參數(shù)(回調(diào)函數(shù))業(yè)務(wù)回調(diào)和兜底回調(diào)
RefundApplicationFormrefundApplicationForm = retryTemplate.execute(
        //RetryCallback
    (RetryCallback<RefundApplicationForm, Throwable>) retryContext -> bankAutoRepay(mRefundApplicationForm,
            supplierBankId),
       //RecoveryCallback兜底
    retryContext -> {
        // 銀行多次重試后異常
        mRefundApplicationForm.setRepayStatCd("100");
        logger.error("銀行多次重試后異常、銀行自動退款異常");
        return mRefundApplicationForm;
    }
);

3.spring retry 注解方式

3.1 啟用Spring Retry支持

為了啟用Spring Retry的功能近范,需要向配置類添加@EnableRetry注釋嘶摊。

@SpringBootApplication
@EnableRetry
public class Launcher {
    public static void main(String[] args) {
        SpringApplication.run(Launcher.class, args);
    }

3.2 啟用重試特性的方法上使用@Retryable注釋

通過此注解設(shè)置重試策略和回退策略。Retryable注解參數(shù):
(1)value:指定發(fā)生的異常進(jìn)行重試
(2)include:和value一樣评矩,默認(rèn)空叶堆,當(dāng)exclude也為空時,所有異常都重試
(3)exclude:指定異常不重試斥杜,默認(rèn)空虱颗,當(dāng)include也為空時沥匈,所有異常都重試
(4)maxAttemps:重試次數(shù),默認(rèn)3
(5)backoff:重試補償機(jī)制忘渔,默認(rèn)沒有

 /**
     * 指定異常CustomRetryException重試高帖,重試最大次數(shù)為4(默認(rèn)是3),重試補償機(jī)制間隔200毫秒
     * 還可以配置exclude,指定異常不充實,默認(rèn)為空
     * @return result
     * @throws CustomRetryException 指定異常
     */
    @Retryable(value = {CustomRetryException.class},maxAttempts = 4,backoff = @Backoff(200))
    String retry() throws CustomRetryException;

@Backoff 注解 重試補償策略:
(1)不設(shè)置參數(shù)時辨萍,默認(rèn)使用FixedBackOffPolicy(指定等待時間)棋恼,重試等待1000ms
(2)設(shè)置delay,使用FixedBackOffPolicy(指定等待設(shè)置delay和maxDealy時锈玉,重試等待在這兩個值之間均態(tài)分布)
(3)設(shè)置delay爪飘、maxDealy、multiplier拉背,使用 ExponentialBackOffPolicy(指數(shù)級重試間隔的實現(xiàn))师崎,multiplier即指定延遲倍數(shù),比如delay=5000L椅棺,multiplier=2,則第一次重試為5秒犁罩,第二次為10秒,第三次為20秒

3.3 @Recover

重試多次失敗后两疚,執(zhí)行兜底方案

@Service
@Slf4j
public class RetryServiceImpl implements RetryService {
    private static int count = 1;
    @Override
    public String retry() throws CustomRetryException {
        log.info("retry{},throw CustomRetryException in method retry",count);
        count ++;
        throw new CustomRetryException("throw custom exception");
    }
    @Recover
    public String recover(Throwable throwable) {
        log.info("Default Retry service test");
        return "Error Class :: " + throwable.getClass().getName();
    }
}

通過Junit進(jìn)行單元測試床估。

    @Test
    void retry() {
        try {
            final String message = retryService.retry();
            log.info("message = "+message);
        } catch (CustomRetryException e) {
            log.error("Error while executing test {}",e.getMessage());
        }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市诱渤,隨后出現(xiàn)的幾起案子丐巫,更是在濱河造成了極大的恐慌,老刑警劉巖勺美,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件递胧,死亡現(xiàn)場離奇詭異,居然都是意外死亡赡茸,警方通過查閱死者的電腦和手機(jī)缎脾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來占卧,“玉大人遗菠,你說我怎么就攤上這事』眩” “怎么了舷蒲?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長友多。 經(jīng)常有香客問我牲平,道長,這世上最難降的妖魔是什么域滥? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任纵柿,我火速辦了婚禮蜈抓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘昂儒。我一直安慰自己沟使,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布渊跋。 她就那樣靜靜地躺著腊嗡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拾酝。 梳的紋絲不亂的頭發(fā)上燕少,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音蒿囤,去河邊找鬼客们。 笑死,一個胖子當(dāng)著我的面吹牛材诽,可吹牛的內(nèi)容都是我干的底挫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼脸侥,長吁一口氣:“原來是場噩夢啊……” “哼建邓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起睁枕,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤官边,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后譬重,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡罐氨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年臀规,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栅隐。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡塔嬉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出租悄,到底是詐尸還是另有隱情谨究,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布泣棋,位于F島的核電站胶哲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏潭辈。R本人自食惡果不足惜鸯屿,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一澈吨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寄摆,春花似錦谅辣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至勾邦,卻和暖如春蚣录,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背检痰。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工包归, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人铅歼。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓公壤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親椎椰。 傳聞我的和親對象是個殘疾皇子厦幅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 準(zhǔn)備好好看看一下spring-cloud的源碼,把其中實現(xiàn)的原理搞清楚慨飘,而不是僅僅會配幾個注解确憨,會配幾個參數(shù),把“...
    沉寂之舟閱讀 14,599評論 0 6
  • 原創(chuàng) Ludovic date 2020-02-25 1塔猾、說在前 在項目開發(fā)過程中,系統(tǒng)間服務(wù)集成調(diào)用這種事是家...
    我們都是架構(gòu)師閱讀 1,989評論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理稽坤,服務(wù)發(fā)現(xiàn)丈甸,斷路器,智...
    卡卡羅2017閱讀 134,651評論 18 139
  • 什么時候用可以重試 遠(yuǎn)程調(diào)用失敗的可以重試 參校失敗不應(yīng)該重試 只讀操作可以重試 冪等寫操作可以重試 非冪等寫操作...
    liuliuzo閱讀 8,885評論 2 11
  • SpringBoot是Spring家族中的一個全新的框架尿褪,它用來簡化Spring應(yīng)用程序的創(chuàng)建和開發(fā)過程睦擂,提供了各...
    細(xì)肥尸丁閱讀 4,326評論 0 0