• 基于redisson实现注解式分布式锁


    依赖版本

    • spring-boot-starter 2.6.3
    • redisson
    <dependency>
        <groupId>org.redissongroupId>
        <artifactId>redisson-spring-boot-starterartifactId>
        <version>3.17.1version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    springboot配置单机版redisson

    spring:
      redis:
        redisson:
          config: |
            singleServerConfig:
              idleConnectionTimeout: 1000
              connectTimeout: 1000
              timeout: 2000
              retryAttempts: 3
              retryInterval: 500
              password: 'xxx'
              subscriptionsPerConnection: 5
              clientName: redissonClient
              address: "redis://127.0.0.1:6379"
              subscriptionConnectionMinimumIdleSize: 1
              subscriptionConnectionPoolSize: 3
              connectionMinimumIdleSize: 4
              connectionPoolSize: 8
              database: 1
              dnsMonitoringInterval: 5000
            threads: 2
            nettyThreads: 4
            codec: ! {}
            transportMode: "NIO"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    新增redisson工具类,避免释放锁的时候锁已过期导致抛异常

    /**
     * @description RedissonClient 工具类
     * @date 2023/9/28
     */
    public class RedissonUtil {
    
        public static boolean tryLockNoThrow(RLock lock, long waitTime, long leaseTime, TimeUnit unit) {
            try {
                return lock.tryLock(waitTime, leaseTime, unit);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return false;
            }
        }
    
        public static void unLockNoThrow(RLock lock) {
            if (!lock.isHeldByCurrentThread()) {
                return;
            }
            try {
                lock.unlock();
            } catch (Exception ex) {}
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    新增分布式锁注解

    • 分布式锁注解,作用与方法上,声明方法加分布式锁
    /**
     * @description 分布式锁
     * @date 2023/9/28
     */
    @Retention(value = RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface DistributedLock {
    
        /**
         * 分布式锁key
         **/
        String lockKey();
    
        /**
         * 获锁等待时间
         **/
        long waitTimeInMill() default 0;
    
        /**
         * 锁自动释放时间
         **/
        long leaseTimeInMill() default 10_000;
    
        /**
         * 获取失败提示
         **/
        String errMsg() default "获取分布式锁失败";
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 分布式锁参数注解,声明方法参数为分布式锁的key变量值
    /**
     * @description 是否为分布式锁的参数注解
     * @date 2023/9/28
     */
    @Target(ElementType.PARAMETER)
    @Retention(value = RetentionPolicy.RUNTIME)
    public @interface LockKey {
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    新增分布式锁注解切面,实现注解式分布式锁功能

    /**
     * @description 分布式锁切面
     * @date 2023/9/28
     */
    @Aspect
    @ConditionalOnClass(DistributedLock.class)
    @Component
    @RequiredArgsConstructor
    @Slf4j
    public class DistributedLockAop {
    
        private final RedissonClient redissonClient;
    
        @Pointcut("@annotation(com.chimelong.common.cache.support.DistributedLock)")
        public void pointCut() {}
    
        @Around("pointCut() && @annotation(lockAnno))")
        public Object handle(ProceedingJoinPoint joinPoint, DistributedLock lockAnno) throws Throwable {
            String lockKey = bindLockKey(joinPoint, lockAnno);
            RLock lock = redissonClient.getLock(lockKey);
            boolean flag = RedissonUtil.tryLockNoThrow(lock, lockAnno.waitTimeInMill(), lockAnno.leaseTimeInMill(), TimeUnit.MILLISECONDS);
            if (!flag) {
                log.error("分布式锁[{}]获取失败", lockAnno.lockKey());
                throw new IllegalStateException(lockAnno.errMsg());
            }
            try {
                return joinPoint.proceed();
            } finally {
                RedissonUtil.unLockNoThrow(lock);
            }
        }
    
        /** 构建分布式锁Key */
        private String bindLockKey(ProceedingJoinPoint joinPoint, DistributedLock lockAnno) {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Annotation[][] annoArr = methodSignature.getMethod().getParameterAnnotations();
            List<Boolean> flagList = new ArrayList<>(4);
    
            for (Annotation[] annotations : annoArr) {
                if (annotations == null || annotations.length == 0) {
                    continue;
                }
                boolean find = Stream.of(annotations).filter(item -> LockKey.class.equals(item.annotationType())).findFirst().isPresent();
                flagList.add(find);
            }
            int flagSize = flagList.size();
            if (flagSize < 1) {
                return lockAnno.lockKey();
            }
    
            StringBuilder lockKeyBuilder = new StringBuilder(lockAnno.lockKey());
            Object[] paramValList = joinPoint.getArgs();
            for (int i = 0; i < paramValList.length; i++) {
                if (i >= flagSize) {
                    break;
                }
                if (!flagList.get(i).booleanValue()) {
                    continue;
                }
                lockKeyBuilder.append(":")
                    .append(paramValList[i]);
            }
            return lockKeyBuilder.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    使用

    @PostMapping("/close")
    @ApiOperation("关闭订单")
    @DistributedLock(lockKey = RedisLockConst.ORDER_PREFIX)
    public R<Boolean> closeUnpaidCompletedOrder(@ApiParam(value = "订单号", required = true) @LockKey @RequestParam String orderCode) {
        return R.ok(true);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    前端工作总结212-账号绑定逻辑复杂
    Mysql 通过binlog伪装master恢复数据库
    B. Inflation-Educational Codeforces Round 103 (Rated for Div. 2)
    Pandas GroupBy 深度总结
    HIVE优化和数据倾斜、合并小文件
    文件服务器管理服务器怎么设置
    车载以太网TSN
    VMware Workstation Pro下载安装
    docker下快速部署openldap与PHPLdapAdmin
    [问题已处理]-在win10上安装prometheus监控
  • 原文地址:https://blog.csdn.net/qq_41633199/article/details/133383581