重試機制:Spring-Retry的使用

學海無涯,旅“途”漫漫,“途”中小記,如有錯誤,敬請指出,在此拜謝!

在日常的開發中,有些場景,我們需要重試某個方法。比如當進行網絡調用時,由於網絡波動導致無法訪問,需要重試幾次。

一、github

https://github.com/spring-projects/spring-retry

二、使用方式

1、Spring-Boot

1.引入依賴

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

2.啓動文件引入@EnableRetry標籤,比如

@SpringBootApplication
@EnableWebMvc
@EnableScheduling
@EnableRetry//開啓重試機制標籤
public class MytestApplication {

    public static void main(String[] args) {
        SpringApplication.run(MytestApplication.class, args);
    }

}

3.需要重試的方法中,增加@Retryable標籤,比如

    /**
     * 待重試的方法
     *
     * @param dto 重試傳輸dto
     * @author lin
     * @since 2019年9月24日
     * <p>
     * value:爲指定重試的異常,只有該異常纔會重試,如果多個異常重試,可以寫做value = {RetryException.class,Exception.class}
     * maxAttempts: 爲重試次數,默認爲3次
     * @Backeoff中的標籤
     * delay: 延遲時間(單位爲毫秒,默認爲0毫秒)
     * multiplier:延遲間隔倍率,比如如果定義延遲爲1秒,延遲倍率爲2,則第一次重試間隔1秒,第二次2秒,第三次4秒,依次類推
     * maxDelay:最大間隔時間
     */
    @Retryable(value = RetryException.class, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
    public void handle(RetryTransferDto dto) {
        log.info("正在處理消息,當前次數第{}次,消息爲{}", dto.getCount(), dto.getMessage());
        if (true) { // 模擬失敗
            dto.setCount(dto.getCount() + 1);
            dto.setMessage(dto.getMessage() + " haha ");
            throw new RetryException("消息處理失敗,當前次數第" + dto.getCount() + "次,消息爲" + dto.getMessage());
        }
    }

此處博主爲了方便計數,增加了一個自定義的傳輸類RetryTransferDto,類的具體內容如下

import lombok.Data;

/**
 * 重試傳輸dto
 *
 * @author lin
 * @since 2019年9月24日
 */
@Data
public class RetryTransferDto {
    // 重試次數
    private int count = 0;
    // 重試內容
    private String message;
}

4.如果在最後一次重試報錯後,想進入特定方法執行某些操作(比如寫日誌等),可以使用@Recover標籤,例如

    /**
     * 重試達到指定次數時,進入此方法
     *
     * @author lin
     * @since 2019年9月24日
     */
    @Recover
    public void recover(RetryException e) {
        log.error("重試達到指定測試", e);
    }

5.日誌輸出如下所示

2019-09-24 10:49:28.572  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在處理消息,當前次數第1次,消息爲haha
2019-09-24 10:49:29.575  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在處理消息,當前次數第2次,消息爲haha haha 
2019-09-24 10:49:31.576  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在處理消息,當前次數第3次,消息爲haha haha  haha 
2019-09-24 10:49:35.577  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在處理消息,當前次數第4次,消息爲haha haha  haha  haha 
2019-09-24 10:49:43.577  INFO 2416 --- [           main] com.lin.mytest.retry.RetryService        : 正在處理消息,當前次數第5次,消息爲haha haha  haha  haha  haha 
2019-09-24 10:49:43.582 ERROR 2416 --- [           main] com.lin.mytest.retry.RetryService        : 重試達到指定測試

org.springframework.retry.RetryException: 消息處理失敗,當前次數第6次,消息爲haha haha  haha  haha  haha  haha 
	at com.lin.mytest.retry.RetryService.handle(RetryService.java:33) ~[classes/:na]
	......

三、注意事項

1.因爲Spring-Retry原理是切面操作,所以pom依賴中也需要有aop的依賴

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

2.因爲是切面操作,所以待重試方法,不能是當前類中調用的方法。打個比方,A類中有方法a和方法b,方法a調用方法b時,在方法b上增加重試機制,此重試方法失效。
3.標籤中maxAttempts、delay、multiplier等參數,需要是常量。如果想動態從yml或者properties的配置文件中獲取,請使用對應的Expression參數。比如

    /**
     * 待重試的方法
     *
     * @param dto 重試傳輸dto
     * @author lin
     * @since 2019年9月24日
     * <p>
     * value:爲指定重試的異常,只有該異常纔會重試,如果多個異常重試,可以寫做value = {RetryException.class,Exception.class}
     * maxAttemptsExpression: 爲重試次數,默認爲3次
     * Backeoff中的標籤
     * delayExpression: 延遲時間(單位爲毫秒,默認爲0毫秒)
     * multiplierExpression:延遲間隔倍率,比如如果定義延遲爲1秒,延遲倍率爲2,則第一次重試間隔1秒,第二次2秒,第三次4秒,依次類推
     * maxDelayExpression:最大間隔時間
     */
    @Retryable(value = RetryException.class, maxAttemptsExpression = "${retry.attempts}", backoff = @Backoff(delayExpression = "${retry.delay}", multiplierExpression = "${retry.multiplier}"))
    public void handle(RetryTransferDto dto) {
        log.info("從配置文件獲取參數,正在處理消息,當前次數第{}次,消息爲{}", dto.getCount(), dto.getMessage());
        if (true) { // 模擬失敗
            dto.setCount(dto.getCount() + 1);
            dto.setMessage(dto.getMessage() + " haha ");
            throw new RetryException("從配置文件獲取參數,消息處理失敗,當前次數第" + dto.getCount() + "次,消息爲" + dto.getMessage());
        }
    }

四、我的測試代碼

碼雲:

https://gitee.com/doubletreelin/mytest.git
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章