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

依赖版本

  • spring-boot-starter 2.6.3
  • redisson
<dependency>
    <groupId>org.redissongroupId>
    <artifactId>redisson-spring-boot-starterartifactId>
    <version>3.17.1version>
dependency>

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"

新增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) {}
    }
}

新增分布式锁注解

  • 分布式锁注解,作用与方法上,声明方法加分布式锁
/**
 * @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 "获取分布式锁失败";

}
  • 分布式锁参数注解,声明方法参数为分布式锁的key变量值
/**
 * @description 是否为分布式锁的参数注解
 * @date 2023/9/28
 */
@Target(ElementType.PARAMETER)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface LockKey {
}

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

/**
 * @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();
    }
}

使用

@PostMapping("/close")
@ApiOperation("关闭订单")
@DistributedLock(lockKey = RedisLockConst.ORDER_PREFIX)
public R<Boolean> closeUnpaidCompletedOrder(@ApiParam(value = "订单号", required = true) @LockKey @RequestParam String orderCode) {
    return R.ok(true);
}

你可能感兴趣的:(分布式)