SpringBoot+Redisson+AOP实现分布式锁,防重复提交

一 、引入jar包

<!-- springboot 对redis的支持-->
<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- springboot 对aop的支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redisson -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.9.1</version>
</dependency>

二、配置文件

#redis配置
spring.redis.host=39.100.91.122
spring.redis.port=6379
spring.redis.database=0
spring.redis.timeout=5000ms
#redisson客户端连接超时时间(ms)
redisson.timeout=10000

三、Redisson代码
3.1 分布式锁接口

/**
 * 分布式锁接口
 */
public interface DistributeLocker {

    /**
     * 加锁
     * @param lockKey key
     */
    void lock(String lockKey);

    /**
     * 释放锁
     *
     * @param lockKey key
     */
    void unlock(String lockKey);

    /**
     * 加锁锁,设置有效期
     *
     * @param lockKey key
     * @param timeout 有效时间,默认时间单位在实现类传入
     */
    void lock(String lockKey, int timeout);

    /**
     * 加锁,设置有效期并指定时间单位
     * @param lockKey key
     * @param timeout 有效时间
     * @param unit    时间单位
     */
    void lock(String lockKey, int timeout, TimeUnit unit);

    /**
     * 尝试获取锁,获取到则持有该锁返回true,未获取到立即返回false
     * @param lockKey
     * @return true-获取锁成功 false-获取锁失败
     */
    boolean tryLock(String lockKey);

    /**
     * 尝试获取锁,获取到则持有该锁leaseTime时间.
     * 若未获取到,在waitTime时间内一直尝试获取,超过watiTime还未获取到则返回false
     * @param lockKey   key
     * @param waitTime  尝试获取时间
     * @param leaseTime 锁持有时间
     * @param unit      时间单位
     * @return true-获取锁成功 false-获取锁失败
     */
    boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit)
            throws InterruptedException;

    /**
     * 锁是否被任意一个线程锁持有
     * @param lockKey
     * @return true-被锁 false-未被锁
     */
    boolean isLocked(String lockKey);
}

3.2 redisson实现分布式锁

/**
 * redisson实现分布式锁接口
 */
public class RedissonDistributeLocker implements DistributeLocker {

    private RedissonClient redissonClient;

    public RedissonDistributeLocker(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    @Override
    public void lock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
    }

    @Override
    public void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.unlock();
    }

    @Override
    public void lock(String lockKey, int leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(leaseTime, TimeUnit.MILLISECONDS);
    }

    @Override
    public void lock(String lockKey, int timeout, TimeUnit unit) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock(timeout, unit);
    }

    @Override
    public boolean tryLock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        return lock.tryLock();
    }

    @Override
    public boolean tryLock(String lockKey, long waitTime, long leaseTime,
                           TimeUnit unit) throws InterruptedException {
        RLock lock = redissonClient.getLock(lockKey);
        return lock.tryLock(waitTime, leaseTime, unit);
    }

    @Override
    public boolean isLocked(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        return lock.isLocked();
    }
}

3.3 redisson锁的工具类

/**
 * redisson锁工具类
 */
public class RedissonLockUtils {

    private static DistributeLocker locker;

    public static void setLocker(DistributeLocker locker) {
        RedissonLockUtils.locker = locker;
    }

    public static void lock(String lockKey) {
        locker.lock(lockKey);
    }

    public static void unlock(String lockKey) {
        locker.unlock(lockKey);
    }

    public static void lock(String lockKey, int timeout) {
        locker.lock(lockKey, timeout);
    }

    public static void lock(String lockKey, int timeout, TimeUnit unit) {
        locker.lock(lockKey, timeout, unit);
    }

    public static boolean tryLock(String lockKey) {
        return locker.tryLock(lockKey);
    }

    public static boolean tryLock(String lockKey, long waitTime, long leaseTime,
                                  TimeUnit unit) throws InterruptedException {
        return locker.tryLock(lockKey, waitTime, leaseTime, unit);
    }

    public static boolean isLocked(String lockKey) {
        return locker.isLocked(lockKey);
    }
}

至此,便可以通过RedissonLockUtils来实现分布式锁。

四、AOP代码
4.1 分布式锁注解

/**
 * 分布式锁注解
 * 添加到方法 ,修饰以@RequestBody JSON对象接收参数的方法
 */
@Target(ElementType.METHOD) //注解在方法
@Retention(RetentionPolicy.RUNTIME)
public @interface RedissonLockAnnotation {

    /**
     * 指定组成分布式锁的key,以逗号分隔。
     * 如:keyParts="name,age",则分布式锁的key为这两个字段value的拼接
     * key=params.getString("name")+params.getString("age")
     */
    String keyParts();
}

4.2 aop实现

/**
 * 分布式锁/防重复提交 aop
 */
@Aspect
@Component
@Slf4j
public class RedissonLockAop {

    /**
     * 切点,拦截被 @RedissonLockAnnotation 修饰的方法
     */
    @Pointcut("@annotation(com.icbc.cxlab.rtc.annotation.RedissonLockAnnotation)")
    public void redissonLockPoint() {
    }

    @Around("redissonLockPoint()")
    @ResponseBody
    public APIResult checkLock(ProceedingJoinPoint pjp) throws Throwable {
        //当前线程名
        String threadName = Thread.currentThread().getName();
        log.info("线程{}------进入分布式锁aop------", threadName);
        //获取参数列表
        Object[] objs = pjp.getArgs();
        //因为只有一个JSON参数,直接取第一个
        JSONObject param = (JSONObject) objs[0];
        //获取该注解的实例对象
        RedissonLockAnnotation annotation = ((MethodSignature) pjp.getSignature()).
                getMethod().getAnnotation(RedissonLockAnnotation.class);
        //生成分布式锁key的键名,以逗号分隔
        String keyParts = annotation.keyParts();
        StringBuffer keyBuffer = new StringBuffer();
        if (StringUtils.isEmpty(keyParts)) {
            log.info("线程{} keyParts设置为空,不加锁", threadName);
            return (APIResult) pjp.proceed();
        } else {
            //生成分布式锁key
            String[] keyPartArray = keyParts.split(",");
            for (String keyPart : keyPartArray) {
                keyBuffer.append(param.getString(keyPart));
            }
            String key = keyBuffer.toString();
            log.info("线程{} 要加锁的key={}", threadName, key);
            //获取锁  等待时间5秒(5秒内获取不到锁尝试一直获取锁),释放时间30秒(加锁30秒后自动释放锁)
            if (RedissonLockUtils.tryLock(key, 5, 30, TimeUnit.SECONDS)) {
                try {
                    log.info("线程{} 获取锁成功", threadName);
                    return (APIResult) pjp.proceed();
                } finally {
                    // 这里判断下当前key是否上锁,不然业务执行时间大于锁自动释放时间后,解锁报异常
                    if(RedissonLockUtils.isLocked(key)){
                        RedissonLockUtils.unlock(key);
                        log.info("线程{} 释放锁", threadName);
                    }
                }
            } else {
                log.info("线程{} 获取锁失败", threadName);
                return new APIResult(-9, "系统繁忙,请稍后重试");
            }
        }

    }
}

五、分布式锁应用

	@PostMapping(value = "testLock", consumes = "application/json")
    @RedissonLockAnnotation(keyParts = "name,age")
    public APIResult testLock(@RequestBody JSONObject params) {
        /**
         * 分布式锁key=params.getString("name")+params.getString("age");
         * 此时name和age均相同的请求不会出现并发问题
         */
        //TODO 业务处理
        return new APIResult(0, "SUCCESS");
    }


————————————————
版权声明:本文为CSDN博主「达摩小老头(Jason)」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36798969/article/details/105004715

  • 0
    点赞
  • 3
    收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 1
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值