分散ロック

多くの状況では、あるコンテキスト (または単一のメッセージ) に対するアクションは排他的な方法で実行する必要があります。1 つの例は、現在のメッセージのメッセージグループの状態をチェックして、グループを解放できるか、それとも将来の検討のためにそのメッセージを追加できるかを判断する必要があるアグリゲーターコンポーネントです。この目的のために、Java は java.util.concurrent.locks.Lock 実装を備えた API を提供します。ただし、アプリケーションがクラスター内で分散および / または実行される場合、問題はさらに複雑になります。この場合のロックは困難であり、排他性要件を達成するには、何らかの共有状態とその特定のアプローチが必要です。

Spring Integration は、ReentrantLock API に基づいたメモリ内 DefaultLockRegistry 実装を備えた LockRegistry 抽象化を提供します。LockRegistry の obtain(Object) メソッドには、特定のコンテキスト用の lock key が必要です。例: アグリゲーターは correlationKey を使用して、そのグループに関する操作をロックします。このようにして、異なるロックを同時に使用できます。この obtain(Object) メソッドは java.util.concurrent.locks.Lock インスタンス (LockRegistry 実装に応じて) を返すため、残りのロジックは標準の Java 同時実行アルゴリズムと同じです。

バージョン 6.2 以降、LockRegistry は、ロック中にいくつかのタスクを実行するための executeLocked() API (このインターフェースの default メソッド) を提供します。この API の動作は、よく知られている JdbcTemplateJmsTemplate、または RestTemplate と似ています。次の例は、この API の使用箇所を示しています。

LockRegistry registry = new DefaultLockRegistry();
...
registry.executeLocked("someLockKey", () -> someExclusiveResourceCall());

このメソッドはタスク呼び出しから例外を再スローし、Lock が中断された場合は InterruptedException をスローします。さらに、Duration を使用するバリアントは、lock.tryLock() が false を返すときに java.util.concurrent.TimeoutException をスローします。

Spring Integration は、分散ロック用に次の LockRegistry 実装を提供します。

Spring Integration AWS [GitHub] (英語) 拡張機能は DynamoDbLockRegistry も実装します。