エラー処理
このマニュアルの冒頭の概要で説明したように、Spring Integration などのメッセージ指向フレームワークの背後にある主な動機の 1 つは、コンポーネント間の疎結合を促進することです。メッセージチャネルは、プロデューサーとコンシューマーがお互いを知る必要がないという点で重要なロールを果たします。ただし、この利点にはいくつかの欠点もあります。疎結合環境では、いくつかのことがより複雑になります。1 つの例はエラー処理です。
メッセージをチャネルに送信するとき、最終的にそのメッセージを処理するコンポーネントは、送信者と同じスレッド内で動作している場合と動作していない場合があります。単純なデフォルト DirectChannel
を使用する場合(<queue>
子要素および 'task-executor' 属性を持たない <channel>
要素の場合)、メッセージ処理は、初期メッセージを送信するのと同じスレッドで行われます。その場合、Exception
がスローされた場合、送信者によってキャッチされる可能性があります(または、キャッチされていない RuntimeException
の場合、送信者を越えて伝播する可能性があります)。これは、通常の Java コールスタックでの例外をスローする操作と同じ動作です。
呼び出し元スレッドで実行されるメッセージフローは、メッセージングゲートウェイ(メッセージングゲートウェイを参照)または MessagingTemplate
(MessagingTemplate
を参照)を介して呼び出される場合があります。どちらの場合でも、デフォルトの動作は、呼び出し元に例外をスローすることです。メッセージングゲートウェイの場合、例外がスローされる方法と、エラーをエラーチャネルにルーティングするようにゲートウェイを構成する方法の詳細については、エラー処理を参照してください。MessagingTemplate
を使用する場合、または MessageChannel
に直接送信する場合、例外は常に呼び出し元にスローされます。
非同期処理を追加すると、状況はかなり複雑になります。たとえば、'channel' 要素が 'queue' 子要素(Java および Annotations 構成の QueueChannel
)を提供する場合、メッセージを処理するコンポーネントは送信者とは異なるスレッドで動作します。ExecutorChannel
を使用する場合も同様です。送信者が Message
をチャネルにドロップし、他のものに移動した可能性があります。標準の Exception
スローテクニックを使用して Exception
をその送信者に直接スローする方法はありません。代わりに、非同期プロセスのエラーを処理するには、エラー処理メカニズムも非同期である必要があります。
Spring Integration は、エラーをメッセージチャネルに発行することで、そのコンポーネントのエラー処理をサポートします。具体的には、Exception
は Spring Integration ErrorMessage
のペイロードになります。その Message
は、'replyChannel' 解決と同様の方法で解決されるメッセージチャネルに送信されます。まず、Exception
が発生したときに処理されていたリクエスト Message
に 'errorChannel' ヘッダー (ヘッダー名は MessageHeaders.ERROR_CHANNEL
定数で定義されています) が含まれている場合、ErrorMessage
がそのチャネルに送信されます。それ以外の場合、エラーハンドラーは、Bean 名が errorChannel
(これも定数として定義されています: IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME
) である「グローバル」チャネルに送信します。
デフォルトの errorChannel
Bean は、フレームワークによって内部的に作成されます。ただし、設定を制御する場合は、独自に定義できます。次の例は、容量が 500
のキューによってサポートされる XML 構成でエラーチャネルを定義する方法を示しています。
@Bean
QueueChannel errorChannel() {
return new QueueChannel(500);
}
<int:channel id="errorChannel">
<int:queue capacity="500"/>
</int:channel>
デフォルトのエラーチャネルは PublishSubscribeChannel です。 |
ここで理解する最も重要なことは、メッセージングベースのエラー処理は、TaskExecutor
内で実行されている Spring Integration タスクによってスローされる例外にのみ適用されるということです。これは、送信者と同じスレッド内で動作するハンドラーによってスローされる例外には適用されません(たとえば、このセクションで前述した DirectChannel
を使用)。
スケジュールされたポーラータスクの実行中に例外が発生すると、それらの例外は ErrorMessage インスタンスにラップされ、'errorChannel' にも送信されます。これは、グローバル taskScheduler Bean に挿入された MessagePublishingErrorHandler を介して行われます。標準の 'errorChannel' 統合フローロジックを使用してエラー処理を実行する必要がある場合は、カスタム taskScheduler にその MessagePublishingErrorHandler を使用することをお勧めします。この場合、登録済みの integrationMessagePublishingErrorHandler Bean を使用できます。 |
グローバルエラー処理を有効にするには、そのチャネルにハンドラーを登録します。例: Spring Integration の ErrorMessageExceptionTypeRouter
を、"errorChannel" にサブスクライブされているエンドポイントのハンドラーとして設定できます。そのルータは、Exception
型に基づいて、エラーメッセージを複数のチャネルに分散できます。
バージョン 4.3.10 以降、Spring Integration は ErrorMessagePublisher
および ErrorMessageStrategy
を提供します。ErrorMessage
インスタンスを公開するための一般的なメカニズムとして使用できます。エラー処理シナリオで呼び出したり、拡張したりできます。ErrorMessageSendingRecoverer
は、このクラスを、RequestHandlerRetryAdvice
などの再試行で使用できる RecoveryCallback
実装として拡張します。ErrorMessageStrategy
は、提供された例外と AttributeAccessor
コンテキストに基づいて ErrorMessage
を構築するために使用されます。MessageProducerSupport
または MessagingGatewaySupport
に注入できます。requestMessage
は、AttributeAccessor
コンテキストの ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY
に保管されます。ErrorMessageStrategy
は、作成した ErrorMessage
の originalMessage
プロパティとして、その requestMessage
を使用できます。DefaultErrorMessageStrategy
はまさにそれを行います。
バージョン 5.2 以降、フレームワークコンポーネントによってスローされるすべての MessageHandlingException
インスタンスには、コンポーネント BeanDefinition
リソースとソースが含まれ、例外からの構成ポイントを決定します。XML 構成の場合、リソースは XML ファイルパスであり、id
属性を持つ XML タグをソースとします。Java&Annotation 構成では、リソースは @Configuration
クラスで、ソースは @Bean
メソッドです。ほとんどの場合、ターゲット統合フローソリューションは、すぐに使用できるコンポーネントとその構成オプションに基づいています。実行時に例外が発生した場合、実行は構成ではなく Bean に対するものであるため、スタックトレースに関与するエンドユーザーコードはありません。Bean 定義のリソースとソースを含めると、構成ミスの可能性を判断し、開発者エクスペリエンスを向上させることができます。
バージョン 5.4.3 以降、デフォルトのエラーチャネルはプロパティ requireSubscribers = true
で構成され、このチャネルにサブスクライバーがない場合(アプリケーションコンテキストが停止している場合など)にメッセージをサイレントに無視しないようになっています。この場合、MessageDispatchingException
がスローされ、受信チャネルアダプターのクライアントコールバックを利用して、再配信またはその他の将来の検討のために、ソースシステム内の元のメッセージを否定的に確認(またはロールバック)することができます。以前の動作を復元するには(ディスパッチされていないエラーメッセージを無視する)、グローバル統合プロパティ spring.integration.channels.error.requireSubscribers
を false
に設定する必要があります。詳細については、グローバルプロパティおよび PublishSubscribeChannel
構成(グローバル errorChannel
を手動で構成する場合)を参照してください。