Master Distributed Locks in Spring Boot with Lock4j: A Complete Guide
This tutorial walks you through using the Lock4j distributed lock component in Spring Boot 3.2.5, covering its features, Maven dependencies, configuration, basic annotation usage, custom key generation, expiration settings, and advanced options like custom executors, key builders, failure strategies, and manual lock handling.
Environment: SpringBoot 3.2.5
1. Introduction
Lock4j is a distributed lock component that offers strong extensibility and multiple backend support (Redis, Redisson, Zookeeper). It uses Spring AOP with the highest precedence, ensuring it does not interfere with other aspects such as declarative transactions.
Simple to use, powerful, highly extensible.
Supports Redisson, RedisTemplate, Zookeeper; can be mixed and extended.
If you need to build your own distributed‑lock solution, the following sections show how to implement it with annotations.
2. Practical Example
2.1 Add Dependencies
<code><properties>
<lock4j.version>2.2.7</lock4j.version>
</properties>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>lock4j-redis-template-spring-boot-starter</artifactId>
<version>${lock4j.version}</version>
</dependency></code>If you prefer Redisson or Zookeeper, add the corresponding starter:
<code><!-- redisson -->
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
<!-- zookeeper -->
<artifactId>lock4j-zookeeper-spring-boot-starter</artifactId></code>Configuration
<code>spring:
data:
redis:
timeout: 10000
connectTimeout: 20000
host: 127.0.0.1
password: xxxooo
# if using Zookeeper
coordinate:
zookeeper:
zkServers: 127.0.0.1:2181,...</code>After configuration, you can use the @Lock4j annotation to acquire locks.
2.2 Basic Usage
<code>@Service
public class StorageService {
private final StorageRepository storageRepository;
public StorageService(StorageRepository storageRepository) {
this.storageRepository = storageRepository;
}
@Lock4j
public void deductStorage(Long storageId, int count) {
// TODO
}
}</code>The default lock timeout is 3 seconds and the lock expires after 30 seconds.
Custom Key
Without specifying a key, Lock4j generates one automatically:
<code>lock4j:com.pack.test.lock4j.StorageServicedeductStorage#</code>You can customize the key with SpEL:
<code>@Lock4j(key = "#storageId")
public void deductStorage(Long storageId, int count) { }</code>Resulting key example:
<code># method call storageService.deductStorage(1, 2);
lock4j:com.pack.test.lock4j.StorageServicedeductStorage#1</code>Or use a plain string (note the required single quotes):
<code>@Lock4j(keys = "'storageId'")
public void deductStorage(...) { }</code>Expiration Settings
Both lock timeout and expiration can be configured:
<code>@Lock4j(keys = {"#storageId"}, expire = 3000, acquireTimeout = 3000)
public void deductStorage(Long storageId, int count) { }</code>expire: lock expiration in milliseconds (must be longer than business processing time). acquireTimeout: time to wait for the lock in milliseconds.
2.3 Advanced Usage
Global Configuration
<code>lock4j:
acquire-timeout: 3000
expire: 30000
primary-executor: com.baomidou.lock.executor.RedisTemplateLockExecutor
lock-key-prefix: lock4j</code>The primary‑executor determines which backend is used first (Redisson > RedisTemplate > Zookeeper).
Custom Executor (Lock Implementation)
<code>@Component
public class JdbcLockExecutor implements LockExecutor<String> {
private final JdbcTemplate jdbcTemplate;
public JdbcLockExecutor(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public String acquire(String lockKey, String lockValue, long expire, long acquireTimeout) {
// TODO; acquire lock
return null;
}
@Override
public boolean releaseLock(String key, String value, String lockInstance) {
// TODO; release lock
return false;
}
}</code>Register it as a Spring bean and use:
<code>@Lock4j(executor = JdbcLockExecutor.class)
public void deductStorage(Long storageId, int count) { }</code>Custom Key Builder
<code>@Component
public class PackLockKeyBuilder implements LockKeyBuilder {
@Override
public String buildKey(MethodInvocation invocation, String[] definitionKeys) {
// TODO; generate key
return null;
}
}</code>Use it with:
<code>@Lock4j(keyBuilderStrategy = PackLockKeyBuilder.class)
public void deductStorage(Long storageId, int count) { }</code>Custom Failure Strategy
<code>@Component
public class PackLockFailureStrategy implements LockFailureStrategy {
@Override
public void onLockFailure(String key, Method method, Object[] arguments) {
// TODO
}
}</code>Apply it via:
<code>@Lock4j(failStrategy = PackLockFailureStrategy.class)
public void deductStorage(Long storageId, int count) { }</code>Manual Lock/Unlock (Non‑Annotation)
<code>private final LockTemplate lockTemplate;
public StorageService(LockTemplate lockTemplate) {
this.lockTemplate = lockTemplate;
}
public void deductStorage(Long storageId, int count) {
String key = "xxxx";
final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedisTemplateLockExecutor.class);
if (null == lockInfo) {
throw new RuntimeException("业务处理中,请稍后再试");
}
try {
// TODO business logic
} finally {
lockTemplate.releaseLock(lockInfo);
}
}
</code>Manual locking is useful for fine‑grained control but is rarely needed.
These examples cover the essential and advanced capabilities of Lock4j for building robust distributed‑lock solutions in Spring Boot.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.