SpringBoot——異常重試Spring-Retry

前言

spring retry是從spring batch獨(dú)立出來的一個(gè)能功能,主要實(shí)現(xiàn)了重試和熔斷。對(duì)于重試是有場(chǎng)景限制的,不是什么場(chǎng)景都適合重試,比如參數(shù)校驗(yàn)不合法、寫操作等(要考慮寫是否冪等)都不適合重試。遠(yuǎn)程調(diào)用超時(shí)、網(wǎng)絡(luò)突然中斷可以重試。在微服務(wù)治理框架中,通常都有自己的重試與超時(shí)配置,比如dubbo可以設(shè)置retries=1,timeout=500調(diào)用失敗只重試1次,超過500ms調(diào)用仍未返回則調(diào)用失敗。在spring retry中可以指定需要重試的異常類型,并設(shè)置每次重試的間隔以及如果重試失敗是繼續(xù)重試還是熔斷(停止重試)。

Spring Retry支持集成到Spring或者Spring Boot項(xiàng)目中,而它支持AOP的切面注入寫法,所以在引入時(shí)必須引入aspectjweaver.jar包。

核心注解

核心注解3個(gè): @EnableRetry、@Retryable 和 @Recover

@EnableRetry
  • 此注解用于開啟重試框架,可以修飾在SpringBoot啟動(dòng)類上面,也可以修飾在需要重試的類上
  • proxyTargetClass:Boolean類型,用于指明代理方式【true:cglib代理,false:jdk動(dòng)態(tài)代理】默認(rèn)使用jdk動(dòng)態(tài)代理
@Retryable注解

被注解的方法發(fā)生異常時(shí)會(huì)重試

  • value:Class[]類型,指定發(fā)生的異常進(jìn)行重試
  • include:Class[]類型,和value一樣,默認(rèn)空,當(dāng)exclude也為空時(shí),所有異常都重試
  • exclude:Class[]類型,指定異常不重試,默認(rèn)空,當(dāng)include也為空時(shí),所有異常都重試
  • maxAttemps:int類型,重試次數(shù),默認(rèn)3
  • backoff:Backoff類型,重試補(bǔ)償機(jī)制,默認(rèn)沒有
@Backoff注解
  • delay:指定延遲后重試,默認(rèn)為1000L,即1s后開始重試。
  • multiplier:指定延遲的倍數(shù),比如delay=5000L,multiplier=2時(shí),第一次重試為5秒后,第二次為10秒,第三次為20秒
@Recover
  • 當(dāng)重試次數(shù)耗盡依然出現(xiàn)異常時(shí),執(zhí)行此異常對(duì)應(yīng)的@Recover方法。
  • 異常類型需要與Recover方法參數(shù)類型保持一致。
  • recover方法返回值需要與重試方法返回值保證一致。

下面是基于Spring Boot項(xiàng)目的集成步驟:

1、引入maven依賴

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

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

2、service

@Service
@Slf4j
public class RemoteService {

    /**
     * 添加重試注解,當(dāng)有異常時(shí)觸發(fā)重試機(jī)制.設(shè)置重試5次,默認(rèn)是3.延時(shí)2000ms再次執(zhí)行,每次延時(shí)提高1.5倍.當(dāng)返回結(jié)果不符合要求時(shí),主動(dòng)報(bào)錯(cuò)觸發(fā)重試.
     * @param count
     * @return
     * @throws Exception
     */
    @Retryable(value = {RemoteAccessException.class }, maxAttempts = 5, backoff = @Backoff(delay = 2000, multiplier = 1.5))
    public String call(Integer count) throws Exception {
        if(count == 10){
            log.info("Remote RPC call do something... {}",LocalTime.now());
            throw new RemoteAccessException("RPC調(diào)用異常");
        }
        return "SUCCESS";
    }

    /**
     * 定義回調(diào),注意異常類型和方法返回值類型要與重試方法一致
     * @param e
     * @return
     */
    @Recover
    public String recover(RemoteAccessException e) {
        log.info("Remote RPC Call fail",e);
        return "recover SUCCESS";
    }
}

3、Controller

@RestController
@RequestMapping("/retry")
@Slf4j
public class RetryController {

    @Autowired
    private RemoteService remoteService;

    @RequestMapping("/show/{count}")
    public String show(@PathVariable Integer count){
        try {
            return remoteService.call(count);
        } catch (Exception e) {
            log.error("RetryController.show Exception",e);
            return "Hello SUCCESS";
        }
    }
}

4、springboot開啟重試

@SpringBootApplication
@EnableRetry
public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class,args);
    }
}

效果

采坑記錄:

1、retry重試機(jī)制無效

由于retry用到了aspect增強(qiáng),所有會(huì)有aspect的坑,就是方法內(nèi)部調(diào)用,會(huì)使aspect增強(qiáng)失效,那么retry當(dāng)然也會(huì)失效。

public class demo {
    public void A() {
        B();
    }

    @Retryable(Exception.class)
    public void B() {
        throw new RuntimeException("retry...");
    }
}

這種情況B()不會(huì)重試。

2、recover回調(diào)報(bào)錯(cuò)

org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method
報(bào)錯(cuò)顯示找不到recovery方法

解決方案就這這兩句話:

  • 1、異常類型需要與Recover方法參數(shù)類型保持一致
  • 2、recover方法返回值需要與重試方法返回值保證一致

異常類型和返回值要一致!

參考:
https://www.cnblogs.com/EasonJim/p/7684649.html

https://www.cnblogs.com/linyufeng/p/13361188.html

?著作權(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)容