Springboot+Redisson封装分布式锁Starter

我们将分布式锁基于缓存扩展了一版,也就是说本starter即有分布式缓存功能,又有分布式锁功能 。而注解版的分布式锁能够解决大多数场景的并核问题,小粒度的Lock锁方式补全其他场景 。1、为什么要使用分布式锁?在分布式,微服务环境中,我们的服务被拆分为很多个,并且每一个服务可能存在多个实例,部署在不同的服务器上 。
此时JVM中的synchronized和lock锁,将只能对自己所在服务的JVM加锁,而跨机器,跨JMV的场景,仍然需要锁的场景就需要使用到分布式锁了 。
2、为什么要使用redis实现分布式锁?因为Redis的性能很好,并且Redis是单线程的,天生线程安全 。
并且Redis的key过期效果与Zookeeper的临时节点的效果相似,都能实现锁超时自动释放的功能 。
而且Redis还可以使用lua脚本来保证redis多条命令实现整体的原子性,Redisson就是使用lua脚本的原子性来实现分布式锁的 。
3、我们如何基于Redisson封装分布式锁?1)、基于RedissonClient实现手动加锁
2)、基于AOP+Redisson封装注解版的分布式锁
3)、将分布式锁功能封装成一个starter, 引入jar包即可实现分布式锁
4、代码实现4.1、整合封装Redisson我们前面封装了基于Redis扩展了SpringCache,封装了
redis-cache-spring-boot-starter 。
我们的分布式锁基于这个模块实现,下面引入依赖 。
引入依赖
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.Apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>itdl-parent</artifactId><groupId>com.itdl</groupId><version>1.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>redis-lock-spring-boot-starter</artifactId><description>Redis实现分布式锁的自定义starter封装模块</description><properties><maven.compiler.source>${JAVA.version}</maven.compiler.source><maven.compiler.target>${java.version}</maven.compiler.target></properties><dependencies><!--redis cache--><dependency><groupId>com.itdl</groupId><artifactId>redis-cache-spring-boot-starter</artifactId></dependency><!--redisson--><dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId></dependency><!--aop--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency></dependencies></project>编写RedisLockConfig配置RedissonClient
/** * Redis实现分布式锁的配置(使用Redisson) */@Configuration// 标识为一个配置项,注入Spring容器@AutoConfigureBefore({CustomRedisConfig.class, CacheNullValuesHandle.class})@ConditionalOnProperty(value = https://www.isolves.com/it/cxkf/bk/2023-08-28/"redis.enable", havingValue = "true")// 开启redis.enable=true时生效@Slf4jpublic class RedisLockConfig {private volatile boolean isCluster = false;private volatile String redisHostsStr = "";@Bean@ConditionalOnMissingBeanpublic RedissonClient redissonClient(CustomRedisProperties redisProperties){// 构建配置Config config =buildConfig(redisProperties);RedissonClient redissonClient = Redisson.create(config);log.info("==============创建redisClient{}版成功:{}==================", isCluster ? "集群": "单机", redisHostsStr);return redissonClient;}private Config buildConfig(CustomRedisProperties redisProperties) {final Config config = new Config();// 根据逗号切割host列表Set hosts = org.springframework.util.StringUtils.commaDelimitedListToSet(redisProperties.getHost());if (CollectionUtils.isEmpty(hosts)){throw new RuntimeException("redis host address cannot be empty");}// 只有一个host, 表示是单机hostif (hosts.size() == 1){String hostPort = hosts.stream().findFirst().get();redisHostsStr = "redis://" + hostPort.trim();config.useSingleServer().setAddress(redisHostsStr).setDatabase(redisProperties.getDatabase()).setPassword(StringUtils.isBlank(redisProperties.getPassword()) ? null : redisProperties.getPassword());isCluster = false;}else {// 集群处理String[] redisHosts = new String[hosts.size()];int i = 0;for (String host : hosts) {String[] split = host.split(":");if (split.length != 2){throw new RuntimeException("host or port err");}redisHosts[i] = "redis://" + host.trim();i++;}redisHostsStr = String.join(",", redisHosts);// 配置集群config.useClusterServers().addNodeAddress(redisHosts).setPassword(StringUtils.isBlank(redisProperties.getPassword()) ? null : redisProperties.getPassword())// 解决Not all slots covered! Only 10922 slots are avAIlable.setCheckSlotsCoverage(false);isCluster = true;}return config;}}


推荐阅读