此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Integration 6.5.1! |
分布式锁
在许多情况下,必须以排他方式执行针对某些上下文(甚至单个消息)的作。
一个例子是聚合器组件,我们必须检查当前消息的消息组状态,以确定我们是否可以释放该组或仅添加该消息以供将来考虑。
为此,Java 提供了一个 APIjava.util.concurrent.locks.Lock
实现。
但是,当应用程序在集群中分布和/或运行时,问题变得更加复杂。
在这种情况下,锁定具有挑战性,需要一些共享状态及其特定方法来实现排他性要求。
Spring Integration 提供了一个LockRegistry
具有内存中的抽象DefaultLockRegistry
基于ReentrantLock
应用程序接口。
这obtain(Object)
方法LockRegistry
需要一个lock key
对于特定上下文。
例如,聚合器使用correlationKey
锁定其组周围的作。
这样可以同时使用不同的锁。
这obtain(Object)
方法返回一个java.util.concurrent.locks.Lock
实例(取决于LockRegistry
实现),因此,其余的逻辑与标准 Java 并发算法相同。
从 6.2 版开始,LockRegistry
提供executeLocked()
API (default
方法)在锁定时执行某些任务。
此 API 的行为类似于众所周知的JdbcTemplate
,JmsTemplate
或RestTemplate
.
以下示例演示了此 API 的用法:
LockRegistry registry = new DefaultLockRegistry();
...
registry.executeLocked("someLockKey", () -> someExclusiveResourceCall());
该方法从任务调用中重新抛出异常,抛出InterruptedException
如果Lock
被打断。
此外,具有Duration
抛出一个java.util.concurrent.TimeoutException
什么时候lock.tryLock()
返回false
.
Spring Integration 提供了这些LockRegistry
分布式锁的实现:
Spring Integration AWS 扩展还实现了一个DynamoDbLockRegistry
.
从 7.0 版开始,DistributedLock
接口的引入,提供了新的方法,lock(Duration ttl
) 和tryLock(long time, TimeUnit unit, Duration ttl)
,以获取具有自定义生存时间 (TTL) 的锁。
双JdbcLock
和RedisLock
实现DistributedLock
接口,支持自定义生存时间的功能。
这LockRegistry<L extends Lock>
现在是扩展Lock
.
这RenewableLockRegistry
界面现在提供新的renewLock(Object lockKey, Duration ttl)
方法,允许您使用自定义生存时间值续订锁。
双JdbcLockRegistry
和RedisLockRegistry
实现LockRegistry
和RenewableLockRegistry
接口与 type 参数DistributedLock
.
下面是如何获取DistributedLock
并使用特定的生存时间值获取它:
DistributedLock lock = registry.obtain("foo");
Duration timeToLive = Duration.ofMillis(500);
if(lock.tryLock(100, TimeUnit.MILLISECONDS, timeToLive)){
try {
// do something
} catch (Exception e) {
// handle exception
} finally{
lock. unlock();
}
}