例外処理

RabbitMQ Java クライアントを使用した多くの操作で、チェック済み例外がスローされる可能性があります。例: IOException インスタンスがスローされるケースが多数あります。RabbitTemplateSimpleMessageListenerContainer、その他の Spring AMQP コンポーネントは、これらの例外をキャッチし、AmqpException 階層内の例外の 1 つに変換します。これらは "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…​MessageConversionExceptionMessageConverter を使用して受信メッセージのペイロードを変換するときにスローされる可能性があります。

  • 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 に設定します。