スレッドセーフ

同時メッセージリスナーコンテナーを使用する場合、単一のリスナーインスタンスがすべてのコンシューマースレッドで呼び出されます。リスナーはスレッドセーフである必要があり、ステートレスリスナーを使用することをお勧めします。リスナーをスレッドセーフにすることができない場合、または同期を追加すると同時実行性を追加するメリットが大幅に減少する場合は、次のいずれかの手法を使用できます。

  • n コンテナーを concurrency=1 で使用し、プロトタイプスコープ MessageListener Bean を使用して、各コンテナーが独自のインスタンスを取得できるようにします (これは、@KafkaListener を使用する場合は不可能です)。

  • 状態を ThreadLocal<?> インスタンスに保持します。

  • シングルトンリスナーに、SimpleThreadScope (または同様のスコープ)で宣言されている Bean に委譲させます。

スレッド状態 (前のリストの 2 番目と 3 番目の項目) のクリーンアップを容易にするために、バージョン 2.2 以降、リスナーコンテナーは各スレッドが終了するときに ConsumerStoppedEvent を発行します。これらのイベントを ApplicationListener または @EventListener メソッドで使用して、スコープから ThreadLocal<?> インスタンスまたは remove() スレッドスコープ Bean を削除できます。SimpleThreadScope は、破棄インターフェースを持つ Bean ( DisposableBean など) を破棄しないため、インスタンスを自分で destroy() する必要があることに注意してください。

デフォルトでは、アプリケーションコンテキストのイベントマルチキャスタは、呼び出しスレッドでイベントリスナーを呼び出します。マルチキャスタを変更して非同期エグゼキュータを使用する場合、スレッドのクリーンアップは効果的ではありません。

仮想スレッドと同時メッセージリスナーコンテナーに関する特別な注意

スレッド調整に synchronized ブロックを引き続き使用する基礎ライブラリクラスには特定の制限があるため、アプリケーションは同時メッセージリスナーコンテナーで仮想スレッドを使用する場合は注意が必要です。仮想スレッドが有効になっている場合、同時実行数が使用可能なプラットフォームスレッド数を超えると、仮想スレッドがプラットフォームスレッドに固定され、競合状態が発生する可能性が高くなります。Spring for Apache Kafka が使用するサードパーティライブラリが仮想スレッドを完全にサポートするように進化するにつれて、メッセージリスナーコンテナーの同時実行数をプラットフォームスレッドの数以下に維持することが推奨されます。このようにして、アプリケーションはスレッドとプラットフォームスレッドに固定されている仮想スレッド間の競合状態を回避します。