彈性功能
從 7.0 版本開始,Spring Framework 核心包含了常見的彈性功能,特別是用於方法呼叫的 @Retryable 和 @ConcurrencyLimit 註解,以及 程式設計式重試支援。
@Retryable
@Retryable 是一個註解,用於指定單個方法(註解宣告在方法級別)或給定類層次結構中所有代理呼叫的方法(註解宣告在型別級別)的重試特性。
@Retryable
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
預設情況下,方法呼叫會在丟擲任何異常時重試:在初次失敗後最多重試 3 次(maxRetries = 3),每次嘗試之間延遲 1 秒。
|
一個 例如,如果 |
如有必要,可以針對每個方法進行專門調整——例如,透過 includes 和 excludes 屬性縮小要重試的異常範圍。提供的異常型別將與失敗呼叫丟擲的異常以及巢狀原因進行匹配。
@Retryable(MessageDeliveryException.class)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
@Retryable(MessageDeliveryException.class) 是 @Retryable(includes = MessageDeliveryException.class) 的快捷方式。 |
|
對於高階用例,您可以透過 自定義謂詞可以與 |
或者,為了進行 4 次重試嘗試,並採用帶有少量抖動的指數退避策略:
@Retryable(
includes = MessageDeliveryException.class,
maxRetries = 4,
delay = 100,
jitter = 10,
multiplier = 2,
maxDelay = 1000)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
最後但同樣重要的是,@Retryable 也適用於具有反應式返回型別的反應式方法,用 Reactor 的重試功能裝飾管道。
@Retryable(maxRetries = 4, delay = 100)
public Mono<Void> sendNotification() {
return Mono.from(...); (1)
}
| 1 | 這個原始的 Mono 將被重試規範修飾。 |
有關各種特性的詳細資訊,請參閱 @Retryable 中可用的註解屬性。
@Retryable 中的幾個屬性具有 String 變體,提供屬性佔位符和 SpEL 支援,作為上述示例中使用的特定型別註解屬性的替代方案。 |
@ConcurrencyLimit
@ConcurrencyLimit 是一個註解,用於指定單個方法(註解宣告在方法級別)或給定類層次結構中所有代理呼叫的方法(註解宣告在型別級別)的併發限制。
@ConcurrencyLimit(10)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
這旨在保護目標資源免受過多執行緒同時訪問,類似於執行緒池或連線池的池大小限制,當達到限制時會阻止訪問。
您可以選擇將限制設定為 1,從而有效鎖定對目標 bean 例項的訪問。
@ConcurrencyLimit(1)
public void sendNotification() {
this.jmsClient.destination("notifications").send(...);
}
這種限制在虛擬執行緒中特別有用,因為通常沒有執行緒池限制。對於非同步任務,這可以透過 SimpleAsyncTaskExecutor 進行約束。對於同步呼叫,此註解透過 ConcurrencyThrottleInterceptor 提供等效行為,該攔截器自 Spring Framework 1.0 以來可用於 AOP 框架的程式設計式使用。
@ConcurrencyLimit 還有一個 limitString 屬性,提供屬性佔位符和 SpEL 支援,作為上面基於 int 的示例的替代方案。 |
啟用彈性方法
與 Spring 許多基於核心註解的功能一樣,@Retryable 和 @ConcurrencyLimit 被設計為可以根據您的選擇啟用或忽略的元資料。啟用彈性註解處理最便捷的方法是在相應的 @Configuration 類上宣告 @EnableResilientMethods。
或者,這些註解可以透過在上下文中定義 RetryAnnotationBeanPostProcessor 或 ConcurrencyLimitBeanPostProcessor bean 來單獨啟用。
程式設計式重試支援
與 @Retryable 提供宣告式方法來為 ApplicationContext 中註冊的 bean 中的方法指定重試語義不同,RetryTemplate 提供了程式設計式 API 來重試任意程式碼塊。
具體來說,RetryTemplate 根據配置的 RetryPolicy 執行並可能重試 Retryable 操作。
var retryTemplate = new RetryTemplate(); (1)
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));
| 1 | 隱式使用 RetryPolicy.withDefaults()。 |
預設情況下,可重試操作將在丟擲任何異常時重試:在初次失敗後最多重試 3 次(maxRetries = 3),每次嘗試之間延遲 1 秒。
如果您只需要自定義重試嘗試次數,可以使用 RetryPolicy.withMaxRetries() 工廠方法,如下所示。
|
可重試操作將至少執行一次,最多重試 例如,如果 |
var retryTemplate = new RetryTemplate(RetryPolicy.withMaxRetries(4)); (1)
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));
| 1 | 顯式使用 RetryPolicy.withMaxRetries(4)。 |
如果您需要縮小要重試的異常類型範圍,可以透過 includes() 和 excludes() 構建器方法實現。提供的異常型別將與失敗操作丟擲的異常以及巢狀原因進行匹配。
var retryPolicy = RetryPolicy.builder()
.includes(MessageDeliveryException.class) (1)
.excludes(...) (2)
.build();
var retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));
| 1 | 指定一個或多個要包含的異常型別。 |
| 2 | 指定一個或多個要排除的異常型別。 |
|
對於高階用例,您可以透過 自定義謂詞可以與 |
以下示例演示如何配置一個 RetryPolicy,該策略具有 4 次重試嘗試和帶有少量抖動的指數退避策略。
var retryPolicy = RetryPolicy.builder()
.includes(MessageDeliveryException.class)
.maxRetries(4)
.delay(Duration.ofMillis(100))
.jitter(Duration.ofMillis(10))
.multiplier(2)
.maxDelay(Duration.ofSeconds(1))
.build();
var retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.execute(
() -> jmsClient.destination("notifications").send(...));
|
一個 |
儘管 RetryPolicy 的工廠方法和構建器 API 涵蓋了大多數常見的配置場景,但您可以實現自定義的 RetryPolicy,以完全控制應觸發重試的異常型別以及要使用的 BackOff 策略。請注意,您還可以透過 RetryPolicy.Builder 中的 backOff() 方法配置自定義的 BackOff 策略。