學海無涯,旅“途”漫漫,“途”中小記,如有錯誤,敬請指出,在此拜謝!
在日常的開發中,有些場景,我們需要重試某個方法。比如當進行網絡調用時,由於網絡波動導致無法訪問,需要重試幾次。
一、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