Spring Retry 簡介
Spring 框架的一個模塊,它提供了自動重試失敗操作的功能。它使用基于注解的配置為 Spring 管理的 bean 提供聲明式重試支持。
通過使用 Spring Retry,您可以指定重試次數(shù)、重試的異常類型、重試之間的延遲以及與重試失敗操作相關(guān)的其他參數(shù)。這在處理不可靠的網(wǎng)絡(luò)連接或外部服務(wù)時非常有用。
要使用 Spring Retry,您需要將 spring-retry 依賴項添加到您的項目中,并使用 @Retryable 注解對需要重試的方法或類進行注解。您還可以使用 @Recover 注解自定義重試行為。
maven 依賴
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
springboot 線程池 配置
/**
* @Package com.ympay.notify.config
* @Description: 線程池
* @author: jinghan
* @date 2019/5/14 11:01
*/
@Configuration
@EnableAsync
@EnableRetry
public class TaskPoolConfig {
/**
* 異步線程池
* @return
*
* 核心線程數(shù)10:線程池創(chuàng)建時候初始化的線程數(shù)
* 最大線程數(shù)20:線程池最大的線程數(shù),只有在緩沖隊列滿了之后才會申請超過核心線程數(shù)的線程
* 緩沖隊列500:用來緩沖執(zhí)行任務(wù)的隊列
* 允許線程的空閑時間60秒:當(dāng)超過了核心線程出之外的線程在空閑時間到達之后會被銷毀
* 線程池名的前綴:設(shè)置好了之后可以方便我們定位處理任務(wù)所在的線程池
* 線程池對拒絕任務(wù)的處理策略:這里采用了CallerRunsPolicy策略,當(dāng)線程池沒有處理能力的時候,該策略會直接在 execute 方法的調(diào)用線程中運行被拒絕的任務(wù);如果執(zhí)行程序已關(guān)閉,則會丟棄該任務(wù)
*
* 說明:setWaitForTasksToCompleteOnShutdown(true)該方法就是這里的關(guān)鍵,
* 用來設(shè)置線程池關(guān)閉的時候等待所有任務(wù)都完成再繼續(xù)銷毀其他的Bean,
* 這樣這些異步任務(wù)的銷毀就會先于Redis線程池的銷毀。同時,這里還設(shè)置了setAwaitTerminationSeconds(60),
* 該方法用來設(shè)置線程池中任務(wù)的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確保應(yīng)用最后能夠被關(guān)閉,而不是阻塞住。
*/
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(500);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("taskExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
return executor;
}
}
異步線程池 + 重試機制
@Async("taskExecutor")
@Retryable(value = RetryException.class, maxAttempts = 5, backoff = @Backoff(delay = 30000L, multiplier = 2))
public void autoRefresh(PlayerSettlementEntity entity) throws RetryException {
if(PlayerSettleEnum.SettlementState.WAIT_SETTLEMENT.getCode().equals(entity.getSettlementState())){
entity = settlementRefreshService.refresh(entity);
}
// 繼續(xù) 重試
if(PlayerSettleEnum.SettlementState.WAIT_SETTLEMENT.getCode().equals(entity.getSettlementState())){
// 記錄當(dāng)前重試
throw new RetryException("待同步 訂單號:"+entity.getSettlementSn());
}
}
在上面的示例中,@Retryable 注解指定了:
- value 參數(shù):指定要重試的異常類型,這里指定為 IOException.class,表示只有在連接到外部服務(wù)時拋出 IOException 異常時才進行重試。
- maxAttempts 參數(shù):指定最大重試次數(shù),這里指定為 5 次。
- backoff 參數(shù):指定重試之間的延遲,這里指定為 3000 毫秒(即 1 秒),表示每次重試之間都要等待 3秒。
- @EnableRetry 注釋添加到我們的 @Configuration 類 啟用 Spring Retry
- @Backoff注解包括以下參數(shù):
- delay:指定在重試之間等待的時間量。默認為1000毫秒。
- multiplier:指定用于計算下一次重試之間的延遲時間的倍數(shù)。
例如,如果當(dāng)前重試的延遲時間為1000毫秒,且倍數(shù)為2,則下一次重試之間的延遲時間將為2000毫秒。默認為1。 - random:指定是否在計算下一次重試之間的延遲時間時使用隨機化。默認為false。
- maxDelay:指定延遲時間的最大值。如果下一次重試之間的計算延遲時間大于此值,則使用此值。默認為Long.MAX_VALUE。
- vmultiplierExpression:指定用于計算下一次重試之間的延遲時間的表達式,可以包括${}占位符和EL表達式。默認為"",即不使用表達式。
使用@Backoff注解可以讓重試策略更加靈活和可配置。
最大嘗試次數(shù)失敗后調(diào)用的方法
在指定方法上標(biāo)記@Recover來開啟重試失敗后調(diào)用的方法(注意,需跟重處理方法在同一個類中)
/**
在指定方法上標(biāo)記@Recover來開啟重試失敗后調(diào)用的方法(注意,需跟重處理方法在同一個類中)
* 重試 日志記錄 防止控制臺打印異常
* @param e
*/
@Recover
public void recover(RetryException e) {
logger.info(e.getMessage());
}
在上面的示例中,@Recover 注解指定了恢復(fù)方法
- recover(),它將在重試失敗后調(diào)用,并且只有在拋出
- RetryException 異常時才會調(diào)用?;謴?fù)方法可以返回默認值或執(zhí)行其他操作。