例外の処理

デフォルトでは、アノテーション付きのリスナーメソッドが例外をスローすると、コンテナーにスローされ、コンテナーとブローカーの構成に応じて、メッセージが再キューイングされ、再配信、破棄、デッドレター交換にルーティングされます。送信者には何も返されません。

バージョン 2.0 以降、@RabbitListener アノテーションには errorHandler と returnExceptions という 2 つの新しい属性があります。

これらはデフォルトでは構成されていません。

errorHandler を使用して、RabbitListenerErrorHandler 実装の Bean 名を指定できます。この関数インターフェースには、次の 1 つのメソッドがあります。

@FunctionalInterface
public interface RabbitListenerErrorHandler {

    Object handleError(Message amqpMessage, org.springframework.messaging.Message<?> message,
              ListenerExecutionFailedException exception) throws Exception;

}

ご覧のとおり、コンテナーから受信した生のメッセージ、メッセージコンバーターによって生成された spring-messaging Message<?> オブジェクト、およびリスナーによってスローされた ( ListenerExecutionFailedException にラップされた) 例外にアクセスできます。エラーハンドラーは、結果を返す (応答として送信される) か、元の例外または新しい例外をスローする (returnExceptions 設定に応じて、コンテナーにスローされるか、送信者に返される) ことができます。

returnExceptions 属性が true の場合、送信者に例外が返されます。例外は RemoteInvocationResult オブジェクトにラップされます。送信者側には、使用可能な RemoteInvocationAwareMessageConverterAdapter があり、RabbitTemplate に構成されている場合、サーバー側の例外を再スローし、AmqpRemoteException にラップされます。サーバー例外のスタックトレースは、サーバーとクライアントのスタックトレースをマージすることによって合成されます。

このメカニズムは通常、Java シリアライゼーションを使用するデフォルトの SimpleMessageConverter でのみ機能します。通常、例外は「Jackson フレンドリー」ではなく、JSON に直列化できません。JSON を使用する場合は、errorHandler を使用して、例外がスローされたときに他の Jackson に適した Error オブジェクトを返すことを検討してください。
バージョン 2.1 では、このインターフェースはパッケージ o.s.amqp.rabbit.listener から o.s.amqp.rabbit.listener.api に移動しました。

バージョン 2.1.7 以降では、メッセージングメッセージヘッダーで Channel が使用可能です。これにより、AcknowledgeMode.MANUAL を使用するときに失敗したメッセージを確認または拒否することができます。

public Object handleError(Message amqpMessage, org.springframework.messaging.Message<?> message,
          ListenerExecutionFailedException exception) {
              ...
              message.getHeaders().get(AmqpHeaders.CHANNEL, Channel.class)
                  .basicReject(message.getHeaders().get(AmqpHeaders.DELIVERY_TAG, Long.class),
                               true);
          }

バージョン 2.2.18 以降では、メッセージ変換例外がスローされた場合、エラーハンドラーが呼び出され、message 引数に null が指定されます。これにより、アプリケーションは何らかの結果を呼び出し元に送信して、不適切な形式のメッセージを受信したことを示すことができます。以前は、このようなエラーはコンテナーによってスローされ、処理されていました。