This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Integration 6.4.3!

Lock Advice

Starting with version 6.5, the LockRequestHandlerAdvice has been introduced. This advice evaluates a lock key against request message and performs LockRegistry.executeLocked() API. The goal of the advice is to achieve exclusive access to the service invocation according to the lockKey context, meaning that different keys may still get concurrent access to the service.

The LockRequestHandlerAdvice requires a LockRegistry, and a static, SpEL or function-based lock key callback. If lockKey is evaluated to null, no locking is held around service call. However, a discardChannel can be provided - and such a message with null key will be sent to this channel instead. Also, a waitLockDuration option can be provided to use Lock.tryLock(long, TimeUnit) API instead of Lock.lockInterruptibly().

Following is a sample how a LockRequestHandlerAdvice can be used:

@Bean
LockRegistry lockRegistry() {
    return new DefaultLockRegistry();
}

@Bean
QueueChannel discardChannel() {
    return new QueueChannel();
}

@Bean
LockRequestHandlerAdvice lockRequestHandlerAdvice(LockRegistry lockRegistry, QueueChannel discardChannel) {
    LockRequestHandlerAdvice lockRequestHandlerAdvice =
            new LockRequestHandlerAdvice(lockRegistry, (message) -> message.getHeaders().get(LOCK_KEY_HEADER));
    lockRequestHandlerAdvice.setDiscardChannel(discardChannel);
    lockRequestHandlerAdvice.setWaitLockDurationExpressionString("'PT1s'");
    return lockRequestHandlerAdvice;
}

AtomicInteger counter = new AtomicInteger();

@ServiceActivator(inputChannel = "inputChannel", adviceChain = "lockRequestHandlerAdvice")
String handleWithDelay(String payload) throws InterruptedException {
    int currentCount = this.counter.incrementAndGet();
    Thread.sleep("longer_process".equals(payload) ? 2000 : 500);
    try {
        return payload + "-" + currentCount;
    }
    finally {
        this.counter.decrementAndGet();
    }
}