在之前的文章中有提到 redisson ,基于 redis 的分布式锁。现在记录一下 springboot 整合 redisson 的过程。
1. pom 依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--Spring Boot -->
<!--支持 Web 应用开发,包含 Tomcat 和 spring-mvc。 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
redisson 3.5.0 和 redisson 2.x 版本有区别,具体得可以去看官方文档,这里使用的 3.5.0
2. 构建 Springboot Java 配置类
配置类使用了 @Profile 注解,因为在实际的应用,可能你本地环境是单机模式,测试或者生产环境是集群模式。
Redisson 还支持主从模式、哨兵模式等,根据自己的需求去进行配置。
@Configuration
public class RedissonManagerConfig {
@Value("${spring.redis.urls}")
private String urls;
@Value("${spring.redis.password}")
private String password;
@Profile("local")
@Bean(name = "redissonClient")
public RedissonClient redissonClientSingle() throws IOException {
RedissonClient redisson = null;
Config config = new Config();
config.useSingleServer().setAddress("redis://" + urls);
redisson = Redisson.create(config);
// 可通过打印redisson.getConfig().toJSON().toString()来检测是否配置成功
return redisson;
}
@Profile("pro")
@Bean(name = "redissonClient")
public RedissonClient redissonClientCluster() throws IOException {
String[] nodes = urls.split(",");
// redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加
for (int i = 0; i < nodes.length; i++) {
nodes[i] = "redis://" + nodes[i];
}
RedissonClient redisson = null;
Config config = new Config();
config.useClusterServers() // 这是用的集群server
.setScanInterval(2000) // 设置集群状态扫描时间
.addNodeAddress(nodes).setPassword(password);
redisson = Redisson.create(config);
// 可通过打印redisson.getConfig().toJSON().toString()来检测是否配置成功
return redisson;
}
}
3. 具体实现类 RedissonDistributedLocker
首先定义一个接口,然后对其进行实现。
public interface AbstractDistributedLocker {
RLock lock(String lockKey);
RLock lock(String lockKey, long timeout);
RLock lock(String lockKey, TimeUnit unit, long timeout);
boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime);
void unlock(String lockKey);
void unlock(RLock lock);
}
@Component
public class RedissonDistributedLocker implements AbstractDistributedLocker {
@Autowired
private RedissonClient redissonClient; // RedissonClient已经由配置类生成,这里自动装配即可
/**
* lock(), 拿不到lock就不罢休,不然线程就一直block
*/
@Override
public RLock lock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock();
return lock;
}
/**
* leaseTime为加锁时间,单位为秒
*/
@Override
public RLock lock(String lockKey, long leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(leaseTime, TimeUnit.SECONDS);
return lock;
}
/**
* timeout为加锁时间,时间单位由unit确定
*/
@Override
public RLock lock(String lockKey, TimeUnit unit, long timeout) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
return lock;
}
/**
* tryLock(),马上返回,拿到lock就返回true,不然返回false。
* 带时间限制的tryLock(),拿不到lock,就等一段时间,超时返回false.
*/
@Override
public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, unit);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 释放 key 的锁
*/
@Override
public void unlock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.unlock();
}
/**
* 释放锁
*/
@Override
public void unlock(RLock lock) {
lock.unlock();
}
}
4. Controller 类测试
最后就可以在你想用加锁的地方进行加锁处理了。
@Controller
@RequestMapping(value = "/")
public class HelloController {
@Autowired
RedissonDistributedLocker redissonDistributedLocker;
@RequestMapping(value = "hello2", method = RequestMethod.GET)
@ResponseBody
public String hello2() throws InterruptedException {
int num = count1.incrementAndGet();
String lock = "lock_key";
try {
if (redissonDistributedLocker.tryLock(lock, TimeUnit.SECONDS, 5L, 10L)) {
// 处理逻辑
redisUtil.incr("test_num1");
// Thread.sleep(1000);
System.out.println("TEST1===========第 " + num + " 次请求===================" + redisUtil.get("test_num1"));
}
} catch (Exception e) {
e.getStackTrace();
} finally {
redissonDistributedLocker.unlock(lock);
}
return "success";
}
}