彈性功能

從 7.0 版本開始,Spring Framework 核心包含了常見的彈性功能,特別是用於方法呼叫的 @Retryable@ConcurrencyLimit 註解,以及 程式設計式重試支援

@Retryable

@Retryable 是一個註解,用於指定單個方法(註解宣告在方法級別)或給定類層次結構中所有代理呼叫的方法(註解宣告在型別級別)的重試特性。

@Retryable
public void sendNotification() {
    this.jmsClient.destination("notifications").send(...);
}

預設情況下,方法呼叫會在丟擲任何異常時重試:在初次失敗後最多重試 3 次(maxRetries = 3),每次嘗試之間延遲 1 秒。

一個 @Retryable 方法將至少被呼叫一次,最多重試 maxRetries 次,其中 maxRetries 是最大重試嘗試次數。具體來說,總嘗試次數 = 1 次初始嘗試 + maxRetries 次嘗試

例如,如果 maxRetries 設定為 4,則 @Retryable 方法將至少被呼叫一次,最多 5 次。

如有必要,可以針對每個方法進行專門調整——例如,透過 includesexcludes 屬性縮小要重試的異常範圍。提供的異常型別將與失敗呼叫丟擲的異常以及巢狀原因進行匹配。

@Retryable(MessageDeliveryException.class)
public void sendNotification() {
    this.jmsClient.destination("notifications").send(...);
}
@Retryable(MessageDeliveryException.class)@Retryable(includes = MessageDeliveryException.class) 的快捷方式。

對於高階用例,您可以透過 @Retryable 中的 predicate 屬性指定一個自定義的 MethodRetryPredicate,該謂詞將用於根據 Method 和給定的 Throwable 來確定是否重試失敗的方法呼叫——例如,透過檢查 Throwable 的訊息。

自定義謂詞可以與 includesexcludes 結合使用;但是,自定義謂詞將始終在 includesexcludes 應用之後應用。

或者,為了進行 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

或者,這些註解可以透過在上下文中定義 RetryAnnotationBeanPostProcessorConcurrencyLimitBeanPostProcessor 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() 工廠方法,如下所示。

可重試操作將至少執行一次,最多重試 maxRetries 次,其中 maxRetries 是最大重試嘗試次數。具體來說,總嘗試次數 = 1 次初始嘗試 + maxRetries 次嘗試

例如,如果 maxRetries 設定為 4,則可重試操作將至少被呼叫一次,最多 5 次。

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.Builder 中的 predicate() 方法指定自定義的 Predicate<Throwable>,該謂詞將用於根據給定的 Throwable 來確定是否重試失敗操作——例如,透過檢查 Throwable 的訊息。

自定義謂詞可以與 includesexcludes 結合使用;但是,自定義謂詞將始終在 includesexcludes 應用之後應用。

以下示例演示如何配置一個 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(...));

一個 RetryListener 可以註冊到 RetryTemplate 中,以響應在關鍵重試階段(重試嘗試之前、重試嘗試之後等)釋出的事件,您可以透過 CompositeRetryListener 組合多個監聽器。

儘管 RetryPolicy 的工廠方法和構建器 API 涵蓋了大多數常見的配置場景,但您可以實現自定義的 RetryPolicy,以完全控制應觸發重試的異常型別以及要使用的 BackOff 策略。請注意,您還可以透過 RetryPolicy.Builder 中的 backOff() 方法配置自定義的 BackOff 策略。

© . This site is unofficial and not affiliated with VMware.