Implementing Distributed Locks with Redisson in Spring Boot
This article demonstrates how to integrate Redisson with Spring Boot to create Redis‑based distributed locks, covering Maven dependencies, YAML configuration, a Redisson configuration class, utility methods for locking and unlocking, and a sample controller that simulates concurrent access to verify lock behavior.
In many interview scenarios candidates are asked about distributed locks such as Redis locks, yet they often lack practical experience; this guide shows how to implement a Redis‑based distributed lock using Redisson within a Spring Boot application.
Adding dependencies
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.10.6</version>
</dependency>YAML configuration
spring:
redis:
host: 47.103.5.190
port: 6379
jedis:
pool:
max-active: 100
max-idle: 10
max-wait: -1
timeout: 5000
database: 0Redisson configuration class (single‑node example)
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}") private String host;
@Value("${spring.redis.port}") private String port;
@Value("${spring.redis.password:}") private String password;
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://" + host + ":" + port);
if (StringUtils.isEmpty(password)) {
config.useSingleServer().setPassword(null);
} else {
config.useSingleServer().setPassword(password);
}
return Redisson.create(config);
}
}Utility class for lock operations
public class RedisLockUtil {
private static DistributedLocker distributedLocker = SpringContextHolder.getBean("distributedLocker", DistributedLocker.class);
public static RLock lock(String lockKey) { return distributedLocker.lock(lockKey); }
public static RLock lock(String lockKey, int timeout) { return distributedLocker.lock(lockKey, timeout); }
public static RLock lock(String lockKey, int timeout, TimeUnit unit) { return distributedLocker.lock(lockKey, unit, timeout); }
public static boolean tryLock(String lockKey, int waitTime, int leaseTime) { return distributedLocker.tryLock(lockKey, TimeUnit.SECONDS, waitTime, leaseTime); }
public static void unlock(String lockKey) { distributedLocker.unlock(lockKey); }
public static void unlock(RLock lock) { distributedLocker.unlock(lock); }
}Distributed locker interface
public interface DistributedLocker {
RLock lock(String lockKey);
RLock lock(String lockKey, int timeout);
RLock lock(String lockKey, TimeUnit unit, int timeout);
boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime);
void unlock(String lockKey);
void unlock(RLock lock);
}Implementation using RedissonClient
@Component
public class RedisDistributedLocker implements DistributedLocker {
@Autowired private RedissonClient redissonClient;
@Override public RLock lock(String lockKey) { RLock lock = redissonClient.getLock(lockKey); lock.lock(); return lock; }
@Override public RLock lock(String lockKey, int leaseTime) { RLock lock = redissonClient.getLock(lockKey); lock.lock(leaseTime, TimeUnit.SECONDS); return lock; }
@Override public RLock lock(String lockKey, TimeUnit unit, int timeout) { RLock lock = redissonClient.getLock(lockKey); lock.lock(timeout, unit); return lock; }
@Override public boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
try { return lock.tryLock(waitTime, leaseTime, unit); } catch (InterruptedException e) { return false; }
}
@Override public void unlock(String lockKey) { redissonClient.getLock(lockKey).unlock(); }
@Override public void unlock(RLock lock) { lock.unlock(); }
}Test controller to simulate concurrent access
@RestController
@RequestMapping("/redisson")
@Slf4j
public class RedissonLockController {
private Integer lockCount = 10;
private Integer count = 10;
private static int threadNum = 10;
@GetMapping("/test")
@ApiOperation(value = "Simulate concurrent test with and without lock")
public void lock() {
CountDownLatch latch = new CountDownLatch(1);
for (int i = 0; i < threadNum; i++) {
MyRunnable r = new MyRunnable(latch);
new Thread(r).start();
}
latch.countDown();
}
private void testLockCount() {
String lockKey = "lock-test";
try {
RedisLockUtil.lock(lockKey, 2, TimeUnit.SECONDS);
lockCount--;
log.info("lockCount value: " + lockCount);
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
RedisLockUtil.unlock(lockKey);
}
}
private void testCount() {
count--;
log.info("count value: " + count);
}
}
public class MyRunnable implements Runnable {
private final CountDownLatch countDownLatch;
public MyRunnable(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; }
@Override public void run() {
try { countDownLatch.await(); } catch (InterruptedException e) { log.error(e.getMessage(), e); }
testCount();
testLockCount();
}
}The test results show that without locking the count-- operation produces out‑of‑order values, while the locked version yields the expected sequential decrement, confirming the effectiveness of the Redisson distributed lock.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
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.
