異常處理

RabbitMQ Java 客戶端的許多操作都可能丟擲受檢查的異常。例如,在許多情況下可能會丟擲 IOException 例項。RabbitTemplateSimpleMessageListenerContainer 和其他 Spring AMQP 元件會捕獲這些異常,並將其轉換為 AmqpException 層次結構中的某個異常。這些異常在 'org.springframework.amqp' 包中定義,AmqpException 是該層次結構的基類。

當監聽器丟擲異常時,它會被包裝在 ListenerExecutionFailedException 中。通常情況下,訊息會被代理拒絕並重新入隊。將 defaultRequeueRejected 設定為 false 會導致訊息被丟棄(或路由到死信交換器)。如 訊息監聽器和非同步情況 中所述,監聽器可以丟擲 AmqpRejectAndDontRequeueException(或 ImmediateRequeueAmqpException)來有條件地控制此行為。

然而,有一類錯誤是監聽器無法控制其行為的。當遇到無法轉換的訊息(例如,無效的 content_encoding 頭)時,在訊息到達使用者程式碼之前會丟擲一些異常。如果 defaultRequeueRejected 設定為 true(預設值)(或丟擲 ImmediateRequeueAmqpException),此類訊息將一次又一次地被重新投遞。在 1.3.2 版本之前,使用者需要編寫自定義的 ErrorHandler,如 異常處理 中所述,以避免這種情況。

從 1.3.2 版本開始,預設的 ErrorHandler 現在是 ConditionalRejectingErrorHandler,它會拒絕(並且不重新入隊)因不可恢復錯誤而失敗的訊息。具體來說,它會拒絕因以下錯誤而失敗的訊息:

  • o.s.amqp…​MessageConversionException:當使用 MessageConverter 轉換傳入訊息有效負載時可能丟擲。

  • o.s.messaging…​MessageConversionException:如果對映到 @RabbitListener 方法時需要額外轉換,則可能由轉換服務丟擲。

  • o.s.messaging…​MethodArgumentNotValidException:如果在監聽器中使用驗證(例如,@Valid)且驗證失敗時可能丟擲。

  • o.s.messaging…​MethodArgumentTypeMismatchException:如果入站訊息被轉換為與目標方法不正確的型別時可能丟擲。例如,引數宣告為 Message<Foo> 但收到了 Message<Bar>

  • java.lang.NoSuchMethodException:在 1.6.3 版本中新增。

  • java.lang.ClassCastException:在 1.6.3 版本中新增。

您可以為該錯誤處理器配置一個 FatalExceptionStrategy 例項,以便使用者可以提供自己的條件訊息拒絕規則 — 例如,一個委託實現到 Spring Retry 的 BinaryExceptionClassifier訊息監聽器和非同步情況)。此外,ListenerExecutionFailedException 現在有一個 failedMessage 屬性,您可以在決策中使用它。如果 FatalExceptionStrategy.isFatal() 方法返回 true,則錯誤處理器將丟擲 AmqpRejectAndDontRequeueException。預設的 FatalExceptionStrategy 在異常被確定為致命時會記錄警告訊息。

自 1.6.3 版本以來,將使用者異常新增到致命列表的一個便捷方法是子類化 ConditionalRejectingErrorHandler.DefaultExceptionStrategy 並重寫 isUserCauseFatal(Throwable cause) 方法,使其對於致命異常返回 true

處理 DLQ 訊息的常見模式是為這些訊息設定一個 time-to-live 以及額外的 DLQ 配置,以便這些訊息過期並被路由回主佇列進行重試。這種技術的缺點是導致致命異常的訊息會無限迴圈。從 2.1 版本開始,ConditionalRejectingErrorHandler 會檢測到導致致命異常的訊息上的 x-death 頭部。該訊息將被記錄並丟棄。您可以透過將 ConditionalRejectingErrorHandler 上的 discardFatalsWithXDeath 屬性設定為 false 來恢復到之前的行為。

從 2.1.9 版本開始,預設情況下,即使容器確認模式為 MANUAL,具有這些致命異常的訊息也會被拒絕且不重新入隊。這些異常通常在監聽器被呼叫之前發生,因此監聽器沒有機會確認或拒絕訊息,導致訊息在佇列中處於未確認狀態。要恢復到之前的行為,請將 ConditionalRejectingErrorHandler 上的 rejectManual 屬性設定為 false
© . This site is unofficial and not affiliated with VMware.