上一章节 通过spring boot 集成了 redis ,本章在上一章的基础上集成 redisson,并实现分布式锁
1.在pom.xml 文件中加入 以下
org.redisson redissoncom.alibaba fastjson
2.新建一个LockProperties 类,内容如下,并添加@ConfigurationProperties 注解,这个注解的作用就是让这个类可以读取到 配置信息,下面会有配置信息的类容
@Getter
@Setter
@ConfigurationProperties(LockProperties.PREFIX)
public class LockProperties {
public static final String PREFIX = "study.lock";
private Boolean enabled = Boolean.FALSE;
private String address = "redis://127.0.0.1:6379";
private String password;
private Integer database = 0;
private Integer poolSize = 20;
private Integer idleSize = 5;
private Integer idleTimeout = 60000;
private Integer connectionTimeout = 3000;
private Integer timeout = 10000;
private Mode mode = Mode.single;
private String masterAddress;
private String[] slaveAddress;
private String masterName;
private String[] sentinelAddress;
private String[] nodeAddress;
public enum Mode {
single,
master,
sentinel,
cluster
}
}
3.在application.yml 中加入 锁配置信息
#项目模块集中配置
study:
#分布式锁配置
lock:
enabled: true
address: redis://127.0.0.1:6379
4.定义LockAutoConfiguration.class
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.*;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
@Configuration
@ConditionalOnClass(RedissonClient.class)
@EnableConfigurationProperties(LockProperties.class)
@ConditionalOnProperty(value = "study.lock.enabled", havingValue = "true")
public class LockAutoConfiguration {
//单机模式
private static Config singleConfig(LockProperties properties) {
Config config = new Config();
SingleServerConfig serversConfig = config.useSingleServer();
serversConfig.setAddress(properties.getAddress());
String password = properties.getPassword();
if (!StringUtils.isEmpty(password)) {
serversConfig.setPassword(password);
}
serversConfig.setDatabase(properties.getDatabase());
serversConfig.setConnectionPoolSize(properties.getPoolSize());
serversConfig.setConnectionMinimumIdleSize(properties.getIdleSize());
serversConfig.setIdleConnectionTimeout(properties.getConnectionTimeout());
serversConfig.setConnectTimeout(properties.getConnectionTimeout());
serversConfig.setTimeout(properties.getTimeout());
return config;
}
//主从模式
private static Config masterSlaveConfig(LockProperties properties) {
Config config = new Config();
MasterSlaveServersConfig serversConfig = config.useMasterSlaveServers();
serversConfig.setMasterAddress(properties.getMasterAddress());
serversConfig.addSlaveAddress(properties.getSlaveAddress());
String password = properties.getPassword();
if (!StringUtils.isEmpty(password)) {
serversConfig.setPassword(password);
}
serversConfig.setDatabase(properties.getDatabase());
serversConfig.setMasterConnectionPoolSize(properties.getPoolSize());
serversConfig.setMasterConnectionMinimumIdleSize(properties.getIdleSize());
serversConfig.setSlaveConnectionPoolSize(properties.getPoolSize());
serversConfig.setSlaveConnectionMinimumIdleSize(properties.getIdleSize());
serversConfig.setIdleConnectionTimeout(properties.getConnectionTimeout());
serversConfig.setConnectTimeout(properties.getConnectionTimeout());
serversConfig.setTimeout(properties.getTimeout());
return config;
}
//哨兵模式
private static Config sentinelConfig(LockProperties properties) {
Config config = new Config();
SentinelServersConfig serversConfig = config.useSentinelServers();
serversConfig.setMasterName(properties.getMasterName());
serversConfig.addSentinelAddress(properties.getSentinelAddress());
String password = properties.getPassword();
if (!StringUtils.isEmpty(password)) {
serversConfig.setPassword(password);
}
serversConfig.setDatabase(properties.getDatabase());
serversConfig.setMasterConnectionPoolSize(properties.getPoolSize());
serversConfig.setMasterConnectionMinimumIdleSize(properties.getIdleSize());
serversConfig.setSlaveConnectionPoolSize(properties.getPoolSize());
serversConfig.setSlaveConnectionMinimumIdleSize(properties.getIdleSize());
serversConfig.setIdleConnectionTimeout(properties.getConnectionTimeout());
serversConfig.setConnectTimeout(properties.getConnectionTimeout());
serversConfig.setTimeout(properties.getTimeout());
return config;
}
//集群模式
private static Config clusterConfig(LockProperties properties) {
Config config = new Config();
ClusterServersConfig serversConfig = config.useClusterServers();
serversConfig.addNodeAddress(properties.getNodeAddress());
String password = properties.getPassword();
if (!StringUtils.isEmpty(password)) {
serversConfig.setPassword(password);
}
serversConfig.setMasterConnectionPoolSize(properties.getPoolSize());
serversConfig.setMasterConnectionMinimumIdleSize(properties.getIdleSize());
serversConfig.setSlaveConnectionPoolSize(properties.getPoolSize());
serversConfig.setSlaveConnectionMinimumIdleSize(properties.getIdleSize());
serversConfig.setIdleConnectionTimeout(properties.getConnectionTimeout());
serversConfig.setConnectTimeout(properties.getConnectionTimeout());
serversConfig.setTimeout(properties.getTimeout());
return config;
}
@Bean
@ConditionalOnMissingBean
public RedisLockClient redisLockClient(LockProperties properties) {
return new RedisLockClientImpl(redissonClient(properties));
}
private static RedissonClient redissonClient(LockProperties properties) {
LockProperties.Mode mode = properties.getMode();
Config config;
switch (mode) {
case sentinel:
config = sentinelConfig(properties);
break;
case cluster:
config = clusterConfig(properties);
break;
case master:
config = masterSlaveConfig(properties);
break;
case single:
config = singleConfig(properties);
break;
default:
config = new Config();
break;
}
return Redisson.create(config);
}
}
5定义要实现的锁
public enum LockType {
REENTRANT,
FAIR
}
6定义锁的API并实现
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
public interface RedisLockClient {
//解锁
void unLock(String lockName,LockType lockType);
//加锁
T lock(String lockName, LockType lockType, long waitTime, long leaseTime, TimeUnit timeUnit, Supplier supplier);
}
@Slf4j
@RequiredArgsConstructor
public class RedisLockClientImpl implements RedisLockClient {
private final RedissonClient redissonClient;
private RLock getLock(String lockName, LockType lockType) {
RLock lock;
if (LockType.REENTRANT == lockType) {
lock = redissonClient.getLock(lockName);
} else {
lock = redissonClient.getFairLock(lockName);
}
return lock;
}
@Override
public void unLock(String lockName, LockType lockType) {
RLock lock = getLock(lockName, lockType);
if (lock.isLocked() && lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
@Override
public T lock(String lockName, LockType lockType, long waitTime, long leaseTime, TimeUnit timeUnit, Supplier supplier) {
try {
RLock rLock = getLock(lockName, lockType);
boolean result = rLock.tryLock(waitTime, leaseTime, timeUnit);
if (result) {
//rLock.lock(leaseTime, timeUnit);
return supplier.get();
} else {
return (T) "获取锁失败";
}
} catch (Throwable e) {
log.info("锁异常");
} finally {
this.unLock(lockName, lockType);
}
return null;
}
}
7.编写代码测试
@GetMapping("testLock")
public String testRedissonLock() {
Supplier checkedSupplier = () -> getServiceTest();
//设置 等待上锁时间1s 设置失效时间100s
String xx = redisLockClient.lock("xx", LockType.REENTRANT, 1, 100, TimeUnit.SECONDS, checkedSupplier);
return xx;
}
// 虚拟的业务方法
public String getServiceTest() {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "OK";
}
效果
第一次访问接口
第二次访问接口 100s之内



