前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redisson 分布式锁封装

Redisson 分布式锁封装

作者头像
默存
发布2022-12-03 12:01:52
8720
发布2022-12-03 12:01:52
举报
文章被收录于专栏:默存默存

项目用 Redisson 分布式锁,但是每个地方的代码除了业务代码,其他都差不多一样的,如果要修改的话,就要修改很多,不只修改一个项目,很麻烦的。

简单封装:

  • 自定义注解
  • 获取锁过程接口

自定义注解

需要在加锁的方法上面贴一个注解,利用 Spring AOP 动态代理的特性进行处理,配置参数值即可。

1.加锁注解
代码语言:javascript
复制
package com.tansci.common.redisson.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @ClassName:Lock.java
 * @ClassPath:com.tansci.common.redisson.annotation.Lock.java
 * @Description: 加锁注解
 *
 * <p>
 * 示例:@Lock(lockKey = "key", businessCode = "A0001", waitTime = 0, leaseTime = 30000)
 * </p>
 * @Author:tanyp
 * @Date:2022/8/30 15:22
 **/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Lock {

    /**
     * 锁的key
     */
    String lockKey() default "";

    /**
     * 业务code
     */
    String businessCode() default "";

    /**
     * 获取锁的等待时间(毫秒)
     */
    int waitTime() default 0;

    /**
     * 释放的时间(毫秒)
     */
    int leaseTime() default 0;

}
2.分布式锁切面
代码语言:javascript
复制
package com.tansci.common.redisson.aop;

import com.tansci.common.redisson.annotation.Lock;
import com.tansci.common.redisson.exception.LockException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName:LockAspect.java
 * @ClassPath:com.tansci.common.redisson.aop.LockAspect.java
 * @Description: 分布式锁切面
 * @Author:tanyp
 * @Date:2022/8/31 9:07
 **/
@Aspect
@Component
public class LockAspect {

    @Autowired
    private RedissonClient redissonClient;

    @Around("@annotation(com.tansci.common.redisson.annotation.Lock)")
    public Object interceptor(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Lock lock = method.getAnnotation(Lock.class);

        String lockKey = getLockKeyName(lock, joinPoint);
        RLock rLock = redissonClient.getLock(lockKey);
        boolean flag = getLock(rLock, lock);
        try {
            if (flag) {
                return joinPoint.proceed();
            } else {
                throw new LockException("网络繁忙,请稍后再试");
            }
        } catch (Exception e) {
            throw new LockException("服务器繁忙,请稍后再试");
        } finally {
            if (flag) {
                if (rLock.isLocked()) {
                    rLock.unlock();
                }
            }
        }
    }

    private String getLockKeyName(Lock lock, ProceedingJoinPoint joinPoint) {
        String lockKeyPrefix = lock.lockKey();
        String businessCode = lock.businessCode();
        if (Objects.nonNull(lockKeyPrefix) && Objects.nonNull(businessCode)) {
            return lockKeyPrefix + ":" + businessCode;
        } else if (Objects.nonNull(lockKeyPrefix)) {
            return lockKeyPrefix;
        } else if (Objects.nonNull(businessCode)) {
            return businessCode;
        } else {
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            return className + "." + methodName;
        }
    }

    private boolean getLock(RLock rLock, Lock lock) throws InterruptedException {
        int waitTime = lock.waitTime();
        int leaseTime = lock.leaseTime();
        boolean flag = false;
        if (waitTime > 0 && leaseTime > 0) {
            flag = rLock.tryLock(waitTime, leaseTime, TimeUnit.MICROSECONDS);
        } else if (leaseTime > 0) {
            flag = rLock.tryLock(0, leaseTime, TimeUnit.MILLISECONDS);
        } else if (waitTime > 0) {
            flag = rLock.tryLock(waitTime, TimeUnit.MILLISECONDS);
        } else {
            flag = rLock.tryLock();
        }
        return flag;
    }

}

3.分布式锁异常处理
代码语言:javascript
复制
package com.tansci.common.redisson.exception;

/**
 * @ClassName:LockException.java
 * @ClassPath:com.tansci.common.redisson.exception.LockException.java
 * @Description: 分布式锁异常处理
 * @Author:tanyp
 * @Date:2022/8/31 9:08
 **/
public class LockException extends RuntimeException {

    /**
     * 异常码
     */
    private int code = 500;

    /**
     * 异常描述
     */
    private String message;

    public LockException(Integer code, String message, Throwable e) {
        super(message, e);
        this.code = code;
        this.message = message;
    }

    public LockException(int code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }

    public LockException(String message) {
        super(message);
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        return code + ": " + message;
    }

}

使用示例
代码语言:javascript
复制
@Lock(lockKeyPrefix = "testKey", businessCode = "A0001", waitTime = 0, leaseTime = 30000)
@GetMapping("/testLock")
public String testLock() throws Exception {
    return "分布式锁注解测试....";
}

获取锁过程接口

直接调用工具类方法,只关心业务逻辑处理部分,可以拓展成多个接口实现不同的业务锁。

代码语言:javascript
复制
package com.tansci.common.redisson.handler;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * @ClassName:RedissonLockHandler.java
 * @ClassPath:com.tansci.common.redisson.handler.RedissonLockHandler.java
 * @Description:redisson分布式锁
 * @Author:tanyp
 * @Date:2022/8/31 9:12
 **/
@Service
@Transactional
public class RedissonLockHandler {

    @Autowired
    private RedissonClient redissonClient;

    /**
     * @MonthName:lock
     * @Description: 获取锁
     * @Author:tanyp
     * @Date:2022/8/31 9:20
     * @Param: [key, waitTime, leaseTime, success, fail]
     * @return:T
     **/
    public <T> T lock(String key, int waitTime, int leaseTime, Supplier<T> success, Supplier<T> fail) throws Exception {
        /**
         * @Autowired
         * private RedissonLockHandler redissonLockHandler;
         *
         * return redissonLockHandler.lock("key",0,30000,()->{
         *    //获取锁成功执行逻辑
         *    return "获取锁成功";
         * },()->{
         *    //获取锁失败执行逻辑
         *    return "获取锁失败";
         * });
         */
        RLock lock = redissonClient.getLock(key);
        boolean flag = lock.tryLock(waitTime, leaseTime, TimeUnit.MILLISECONDS);
        try {
            if (flag) {
                return success.get();
            } else {
                return fail.get();
            }
        } finally {
            if (flag) {
                if (lock.isLocked()) {
                    lock.unlock();
                }
            }
        }
    }

}

使用示例
代码语言:javascript
复制
@Autowired
private RedissonLockHandler redissonLockHandler;

@GetMapping("/testLock")
public String testLock() throws Exception {
    return redissonLockHandler.lock("testKey",0,30000,()->{
        // 获取锁成功执行逻辑
        return "获取锁成功";
    },()->{
        // 获取锁失败执行逻辑
        return "获取锁失败";
    });
}

区别

  • 第一种适用于方法级别的,代码更优雅舒服一些。
  • 第二种通用,整个方法全部代码块和部分代码块都可,业务拓展性更高。
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-08-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 自定义注解
    • 1.加锁注解
      • 2.分布式锁切面
        • 3.分布式锁异常处理
          • 使用示例
          • 获取锁过程接口
            • 使用示例
            • 区别
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档