Spring Boot 集成 Redisson分布式锁(注解版) 您所在的位置:网站首页 redis和redission分别如何做分布式锁 Spring Boot 集成 Redisson分布式锁(注解版)

Spring Boot 集成 Redisson分布式锁(注解版)

2024-06-30 11:01| 来源: 网络整理| 查看: 265

        Redisson 是一种基于 Redis 的 Java 驻留集群的分布式对象和服务库,可以为我们提供丰富的分布式锁和线程安全集合的实现。在 Spring Boot 应用程序中使用 Redisson 可以方便地实现分布式应用程序的某些方面,例如分布式锁、分布式集合、分布式事件发布和订阅等。本篇是一个使用 Redisson 实现分布式锁的详细示例,在这个示例中,我们定义了DistributedLock注解,它可以标注在方法上,配合DistributedLockAspect切面以及IDistributedLock分布式锁封装的接口,来实现redisson 分布式锁的 API 调用。

Spring Boot 集成 Redisson

 1、在 pom.xml 文件中添加 Redisson 的相关依赖

org.redisson redisson-spring-boot-starter 3.16.1

2、在 application.yml 中配置 Redisson单机模式 的连接信息和相关参数

spring: redis: host: localhost port: 6379 password: null redisson: codec: org.redisson.codec.JsonJacksonCodec threads: 4 netty: threads: 4 single-server-config: address: "redis://localhost:6379" password: null database: 0

3、Redission还支持主从、集群、哨兵配置

//主从模式 spring: redis: sentinel: master: my-master nodes: localhost:26379,localhost:26389 password: your_password redisson: master-slave-config: master-address: "redis://localhost:6379" slave-addresses: "redis://localhost:6380,redis://localhost:6381" password: ${spring.redis.password} // 集群模式 spring: redis: cluster: nodes: localhost:6379,localhost:6380,localhost:6381,localhost:6382,localhost:6383,localhost:6384 password: your_password redisson: cluster-config: node-addresses: "redis://localhost:6379,redis://localhost:6380,redis://localhost:6381,redis://localhost:6382,redis://localhost:6383,redis://localhost:6384" password: ${spring.redis.password} // 哨兵模式 spring: redis: sentinel: master: my-master nodes: localhost:26379,localhost:26389 password: your_password redisson: sentinel-config: master-name: my-master sentinel-addresses: "redis://localhost:26379,redis://localhost:26380,redis://localhost:26381" password: ${spring.redis.password}  本地封装Redisson 分布式锁 1、定义IDistributedLock分布式锁接口 public interface IDistributedLock { /** * 获取锁,默认30秒失效,失败一直等待直到获取锁 * * @param key 锁的key * @return 锁对象 */ ILock lock(String key); /** * 获取锁,失败一直等待直到获取锁 * * @param key 锁的key * @param lockTime 加锁的时间,超过这个时间后锁便自动解锁; 如果lockTime为-1,则保持锁定直到显式解锁 * @param unit {@code lockTime} 参数的时间单位 * @param fair 是否公平锁 * @return 锁对象 */ ILock lock(String key, long lockTime, TimeUnit unit, boolean fair); /** * 尝试获取锁,30秒获取不到超时异常,锁默认30秒失效 * * @param key 锁的key * @param tryTime 获取锁的最大尝试时间 * @return * @throws Exception */ ILock tryLock(String key, long tryTime) throws Exception; /** * 尝试获取锁,获取不到超时异常 * * @param key 锁的key * @param tryTime 获取锁的最大尝试时间 * @param lockTime 加锁的时间 * @param unit {@code tryTime @code lockTime} 参数的时间单位 * @param fair 是否公平锁 * @return * @throws Exception */ ILock tryLock(String key, long tryTime, long lockTime, TimeUnit unit, boolean fair) throws Exception; /** * 解锁 * * @param lock * @throws Exception */ void unLock(Object lock); /** * 释放锁 * * @param lock * @throws Exception */ default void unLock(ILock lock) { if (lock != null) { unLock(lock.getLock()); } } } 2、IDistributedLock实现类 @Slf4j @Component public class RedissonDistributedLock implements IDistributedLock { @Resource private RedissonClient redissonClient; /** * 统一前缀 */ @Value("${redisson.lock.prefix:bi:distributed:lock}") private String prefix; @Override public ILock lock(String key) { return this.lock(key, 0L, TimeUnit.SECONDS, false); } @Override public ILock lock(String key, long lockTime, TimeUnit unit, boolean fair) { RLock lock = getLock(key, fair); // 获取锁,失败一直等待,直到获取锁,不支持自动续期 if (lockTime > 0L) { lock.lock(lockTime, unit); } else { // 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s lock.lock(); } return new ILock(lock, this); } @Override public ILock tryLock(String key, long tryTime) throws Exception { return this.tryLock(key, tryTime, 0L, TimeUnit.SECONDS, false); } @Override public ILock tryLock(String key, long tryTime, long lockTime, TimeUnit unit, boolean fair) throws Exception { RLock lock = getLock(key, fair); boolean lockAcquired; // 尝试获取锁,获取不到超时异常,不支持自动续期 if (lockTime > 0L) { lockAcquired = lock.tryLock(tryTime, lockTime, unit); } else { // 具有Watch Dog 自动延期机制 默认续30s 每隔30/3=10 秒续到30s lockAcquired = lock.tryLock(tryTime, unit); } if (lockAcquired) { return new ILock(lock, this); } return null; } /** * 获取锁 * * @param key * @param fair * @return */ private RLock getLock(String key, boolean fair) { RLock lock; String lockKey = prefix + ":" + key; if (fair) { // 获取公平锁 lock = redissonClient.getFairLock(lockKey); } else { // 获取普通锁 lock = redissonClient.getLock(lockKey); } return lock; } @Override public void unLock(Object lock) { if (!(lock instanceof RLock)) { throw new IllegalArgumentException("Invalid lock object"); } RLock rLock = (RLock) lock; if (rLock.isLocked()) { try { rLock.unlock(); } catch (IllegalMonitorStateException e) { log.error("释放分布式锁异常", e); } } } }  3、定义ILock锁对象 import lombok.AllArgsConstructor; import lombok.Getter; import java.util.Objects; /** *

* RedissonLock 包装的锁对象 实现AutoCloseable接口,在java7的try(with resource)语法,不用显示调用close方法 *

* @since 2023-06-08 16:57 */ @AllArgsConstructor public class ILock implements AutoCloseable { /** * 持有的锁对象 */ @Getter private Object lock; /** * 分布式锁接口 */ @Getter private IDistributedLock distributedLock; @Override public void close() throws Exception { if(Objects.nonNull(lock)){ distributedLock.unLock(lock); } } } 4、注入IDistributedLock接口使用示例 // 定义接口 public interface IProductSkuSupplierMeasureService { /** * 保存SKU供应商供货信息 * * @param dto * @return * Boolean saveSupplierInfo(ProductSkuSupplierInfoDTO dto); /** * 编辑SKU供应商供货信息 * * @param dto * @return */ Boolean editSupplierInfo(ProductSkuSupplierInfoDTO dto); }

手动释放锁示例 

// 实现类 @Service public class ProductSkuSupplierMeasureServiceImpl implements IProductSkuSupplierMeasureService { @Resource private IDistributedLock distributedLock; @Override @Transactional(rollbackFor = Exception.class) public Boolean saveSupplierInfo(ProductSkuSupplierInfoDTO dto) { // 手动释放锁 String sku = dto.getSku(); ILock lock = null; try { lock = distributedLock.lock(dto.getSku(),10L, TimeUnit.SECONDS, false); if (Objects.isNull(lock)) { throw new BusinessException("Duplicate request for method still in process"); } // 业务代码 }catch (BusinessException e) { throw new BusinessException(e.getMessage()); } catch (Exception e) { log.error("保存异常", e); throw new BusinessException (e.getMessage()); } finally { if (Objects.nonNull(lock)) { distributedLock.unLock(lock); } } return Boolean.TRUE; } }

 使用try-with-resources 语法糖自动释放锁

// 实现类 @Service public class ProductSkuSupplierMeasureServiceImpl implements IProductSkuSupplierMeasureService { @Resource private IDistributedLock distributedLock; @Override @Transactional(rollbackFor = Exception.class) public Boolean editSupplierInfo(ProductSkuSupplierInfoDTO dto) { String sku = dto.getSku(); // try-with-resources 语法糖自动释放锁 try(ILock lock = distributedLock.lock(dto.getSku(),10L, TimeUnit.SECONDS, false)) { if(Objects.isNull(lock)){ throw new BusinessException ("Duplicate request for method still in process"); } // 业务代码 }catch (BusinessException e) { throw new BusinessException (e.getMessage()); } catch (Exception e) { log.error("修改异常", e); throw new BusinessException ("修改异常"); } return Boolean.TRUE; } } 5、使用AOP切面实现分布式锁的绑定

  定义DistributedLock注解

@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DistributedLock { /** * 保证业务接口的key的唯一性,否则失去了分布式锁的意义 锁key * 支持使用spEl表达式 */ String key(); /** * 保证业务接口的key的唯一性,否则失去了分布式锁的意义 锁key 前缀 */ String keyPrefix() default ""; /** * 是否在等待时间内获取锁,如果在等待时间内无法获取到锁,则返回失败 */ boolean tryLok() default false; /** * 获取锁的最大尝试时间 ,会尝试tryTime时间获取锁,在该时间内获取成功则返回,否则抛出获取锁超时异常,tryLok=true时,该值必须大于0。 * */ long tryTime() default 0; /** * 加锁的时间,超过这个时间后锁便自动解锁 */ long lockTime() default 30; /** * tryTime 和 lockTime的时间单位 */ TimeUnit unit() default TimeUnit.SECONDS; /** * 是否公平锁,false:非公平锁,true:公平锁 */ boolean fair() default false; }

 定义DistributedLockAspect Lock切面

@Aspect @Slf4j public class DistributedLockAspect { @Resource private IDistributedLock distributedLock; /** * SpEL表达式解析 */ private SpelExpressionParser spelExpressionParser = new SpelExpressionParser(); /** * 用于获取方法参数名字 */ private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer(); @Pointcut("@annotation(com.yt.bi.common.redis.distributedlok.annotation.DistributedLock)") public void distributorLock() { } @Around("distributorLock()") public Object around(ProceedingJoinPoint pjp) throws Throwable { // 获取DistributedLock DistributedLock distributedLock = this.getDistributedLock(pjp); // 获取 lockKey String lockKey = this.getLockKey(pjp, distributedLock); ILock lockObj = null; try { // 加锁,tryLok = true,并且tryTime > 0时,尝试获取锁,获取不到超时异常 if (distributedLock.tryLok()) { if(distributedLock.tryTime()


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有