spring-retry解決重試

一、前言

在日常開發(fā)過程中,難免會(huì)與第三方接口發(fā)生交互,例如:短信發(fā)送、遠(yuǎn)程服務(wù)調(diào)用、爭(zhēng)搶鎖等場(chǎng)景,當(dāng)正常調(diào)用發(fā)生異常時(shí),例如:網(wǎng)絡(luò)抖動(dòng),這些間歇性的異常在一段時(shí)候之后會(huì)自行恢復(fù),程序?yàn)榱烁咏巡⑶腋蝗菀壮霈F(xiàn)故障,需要重新觸發(fā)業(yè)務(wù)操作,以防止間歇性的異常對(duì)程序照成的影響。常用的重試策略,比如通過 while 循環(huán)手動(dòng)重復(fù)調(diào)用或是通過 JDK/CGLib 動(dòng)態(tài)代理的方式來進(jìn)行重試。但是這種方法比較笨重,且對(duì)原有邏輯代碼的入侵性比較大。

二、引入spring-retry

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

這里我們還引入了 aop 的依賴,因?yàn)?spring-retry 的原理就是基于 aop 來實(shí)現(xiàn)的。

三、開啟spring-retry

啟動(dòng)類上增加注解@EnableRetry

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

四、@Retryable

在需要重試的方法上增加注解@Retryable,表示該方法需要重試。

@Component
public class TestRetry {

    int a = 0;

    @Retryable(value = {RuntimeException.class}, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
    public String test() {
        a++;
        System.out.println(a + " - " + System.currentTimeMillis());
        if (a < 10) {
            throw new RuntimeException("未滿足條件");
        }
        return "執(zhí)行成功";
    }
}
4.1 @Retryable 注解
  • value,可重試的異常類型。含義同include。默認(rèn)為空(如果excludes也為空,則重試所有異常)
  • include:可重試的異常類型。默認(rèn)為空(如果excludes也為空,則重試所有異常)
  • exclude:無需重試的異常類型。默認(rèn)為空(如果includes也為空,則重試所有異常)
  • maxAttempts,最大重試次數(shù)(包括第一次失敗),默認(rèn)為3次
  • backoff:重試等待策略,下面會(huì)在@Backoff中介紹
  • recover,表示重試次數(shù)到達(dá)最大重試次數(shù)后的回調(diào)方法
4.2 @Backoff 注解
  • delay,重試之間的等待時(shí)間(以毫秒為單位)
  • maxDelay,重試之間的最大等待時(shí)間(以毫秒為單位)
  • multiplier,指定延遲的倍數(shù)
  • delayExpression,重試之間的等待時(shí)間表達(dá)式
  • maxDelayExpression,重試之間的最大等待時(shí)間表達(dá)式
  • multiplierExpression,指定延遲的倍數(shù)表達(dá)式
  • random,隨機(jī)指定延遲時(shí)間

五、重試耗盡

當(dāng)重試耗盡時(shí),RetryOperations 可以將控制傳遞給另一個(gè)回調(diào),即 RecoveryCallback。Spring-Retry 還提供了@Recover注解,用于@Retryable重試失敗后處理方法。若不需要重試失敗后的處理方法,則不寫回調(diào)方法,重試耗盡后拋出異常。

@Recover
public String recoverTest(RuntimeException e) {
    return "回調(diào)方法-" + e.getMessage();
}

說明:

  • 方法的返回值必須與@Retryable 方法一致
  • 方法的第一個(gè)參數(shù),必須是 Throwable 類型的,建議是與@Retryable 配置的異常一致,其他的參數(shù),需要哪個(gè)參數(shù),寫進(jìn)去就可以了(@Recover 方法中有的)
  • 該回調(diào)方法與重試方法寫在同一個(gè)實(shí)現(xiàn)類里面

若同一個(gè)實(shí)現(xiàn)類中有多個(gè)回調(diào)方法,我們需要使用 recover 屬性指定回調(diào)的方法名

@Component
public class TestRetry {

    int a = 0;

    @Retryable(recover = "recoverTest1", value = {RuntimeException.class}, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
    public String test() {
        a++;
        System.out.println(a + " - " + System.currentTimeMillis());
        if (a < 10) {
            throw new RuntimeException("未滿足條件");
        }
        return "執(zhí)行成功";
    }

    @Recover
    public String recoverTest(RuntimeException e) {
        return "回調(diào)方法-" + e.getMessage();
    }

    @Recover
    public String recoverTest1(RuntimeException e) {
        return "回調(diào)方法1-" + e.getMessage();
    }
}

指定了回調(diào)方法為 recoverTest1

六、注意事項(xiàng)

  • 由于是基于AOP實(shí)現(xiàn),所以不支持類里自調(diào)用方法
  • 如果重試失敗需要給 @Recover 注解的方法做后續(xù)處理,那這個(gè)重試的方法不能有返回值,只能是 void
  • 方法內(nèi)不能使用 try catch,只能往外拋異常
  • @Recover 注解來開啟重試失敗后調(diào)用的方法(注意,需跟重處理方法在同一個(gè)類中),此注解注釋的方法參數(shù)一定要是 @Retryable 拋出的異常,否則無法識(shí)別,可以在該方法中進(jìn)行日志處理。

轉(zhuǎn)載自:【SpringBoot】75、SpringBoot中使用spring-retry輕松解決重試

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容