使用自定义注解实现redisson分布式锁

作者:SillinessPlus 时间:2021-09-30 18:31:22 

自定义注解实现redisson分布式锁

自定义注解

package com.example.demo.annotation;
import java.lang.annotation.*;
/**
* desc: 自定义 redisson 分布式锁注解
*
* @author: 邢阳
* @mail: xydeveloper@126.com
* @create 2021-05-28 16:50
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Lock {
   /**
    * 锁的key spel 表达式
    *
    * @return
    */
   String key();
   /**
    * 持锁时间
    *
    * @return
    */
   long keepMills() default 20;
   /**
    * 没有获取到锁时,等待时间
    *
    * @return
    */
   long maxSleepMills() default 30;
}

aop解析注解

package com.example.demo.utils;
import com.example.demo.annotation.Lock;
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.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* desc: 解析 自定义 redisson 分布式锁注解
*
* @author: 邢阳
* @mail: xydeveloper@126.com
* @create 2021-05-28 16:50
*/
@Aspect
@Component
public class LockAspect {
   @Autowired
   private RedissonClient redissonClient;
   /**
    * 用于SpEL表达式解析.
    */
   private final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
   /**
    * 用于获取方法参数定义名字.
    */
   private final DefaultParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer();
   @Around("@annotation(com.example.demo.annotation.Lock)")
   public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
       Object object = null;
       RLock lock = null;
       try {
           // 获取注解实体信息
           Lock lockEntity = (((MethodSignature) proceedingJoinPoint.getSignature()).getMethod())
                   .getAnnotation(Lock.class);
           // 根据名字获取锁实例
           lock = redissonClient.getLock(getKeyBySpeL(lockEntity.key(), proceedingJoinPoint));
           if (Objects.nonNull(lock)) {
               if (lock.tryLock(lockEntity.maxSleepMills(), lockEntity.keepMills(), TimeUnit.SECONDS)) {
                   object = proceedingJoinPoint.proceed();
               } else {
                   throw new RuntimeException();
               }
           }
       } finally {
           if (Objects.nonNull(lock) && lock.isHeldByCurrentThread()) {
               lock.unlock();
           }
       }
       return object;
   }
   /**
    * 获取缓存的key
    *
    * key 定义在注解上,支持SPEL表达式
    *
    * @return
    */
   public String getKeyBySpeL(String spel, ProceedingJoinPoint proceedingJoinPoint) {
       MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
       String[] paramNames = defaultParameterNameDiscoverer.getParameterNames(methodSignature.getMethod());
       EvaluationContext context = new StandardEvaluationContext();
       Object[] args = proceedingJoinPoint.getArgs();
       for (int i = 0; i < args.length; i++) {
           context.setVariable(paramNames[i], args[i]);
       }
       return String.valueOf(spelExpressionParser.parseExpression(spel).getValue(context));
   }
}

service中使用注解加锁使用

/**
* desc: 锁
*
* @author: 邢阳
* @mail: xydeveloper@126.com
* @create 2021-05-28 17:58
*/
@Service
public class LockService {
 @Lock(key = "#user.id", keepMills = 10, maxSleepMills = 15)
   public String lock(User user) {
       System.out.println("持锁");
       return "";
   }
}

redisson分布式锁应用

分布式架构一定会用到分布式锁。目前公司使用的基于redis的redisson分布式锁。

应用场景

1.订单修改操作,首先要获取该订单的分布式锁,能取到才能去操作。lockey可以是订单的主键id。

2.库存操作,也要按照客户+仓库+sku维护锁定该库存,进行操作。

代码:

Redisson管理类

public class RedissonManager {
    private static RedissonClient redisson;
    static {
        Config config = new Config();
        config.useSentinelServers()
                .addSentinelAddress("redis://127.0.0.1:26379","redis://127.0.0.1:7301", "redis://127.0.0.1:7302")
                .setMasterName("mymaster")
                .setReadMode(ReadMode.SLAVE)
                .setTimeout(10000).setDatabase(0).setPassword("123***");
        redisson = Redisson.create(config);
    }
 
    /**
     * 获取Redisson的实例对象
     * @return
     */
    public static RedissonClient getRedisson(){ return redisson;}
}

分布式锁

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
public class DistributedLock {
    private static RedissonClient redissonClient = RedissonManager.getRedisson();
    public static boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            return lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            return false;
        }
    }
    public static void unlock(String lockKey) {
        RLock lock = redissonClient.getLock(lockKey);
        lock.unlock();
    }
}

测试类

public class RedissonTest {
    public static void main(String[] args) throws Exception{
        Thread.sleep(2000L);
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                try {
                    //tryLock,第三个参数是等待时间,5秒内获取不到锁,则直接返回。 第四个参数 30是30秒后强制释放
                    boolean hasLock = DistributedLock.tryLock("lockKey", TimeUnit.SECONDS,5,30);
                    //获得分布式锁
                    if(hasLock){
                        System.out.println("idea1: " + Thread.currentThread().getName() + "获得了锁");
                       
                    /**
                         * 由于在DistributedLock.tryLock设置的等待时间是5s,
                         * 所以这里如果休眠的小于5秒,这第二个线程能获取到锁,
                         *  如果设置的大于5秒,则剩下的线程都不能获取锁。可以分别试试2s,和8s的情况
                         */
                        Thread.sleep(10000L);
                        DistributedLock.unlock("lockKey");
                    } else {
                        System.out.println("idea1: " + Thread.currentThread().getName() + "无法获取锁");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } 
            }) .start();
        }
    }
}

我们再打开一个idea,可以把代码复制一份。同事启动两个RedissonTest ,模拟了并发操作。

测试结果:

idea2: Thread-1获得了锁
idea2: Thread-0无法获取锁
idea2: Thread-2无法获取锁
 
 
idea1: Thread-2无法获取锁
idea1: Thread-0无法获取锁
idea1: Thread-1无法获取锁

从测试结果发现,最后是只能有一个idea的一个线程能获取到锁。

来源:https://blog.csdn.net/weixin_43319539/article/details/117365044

标签:注解,redisson,分布式锁
0
投稿

猜你喜欢

  • C++实现softmax函数的面试经验

    2023-06-16 02:07:47
  • Springboot启动不检查JPA的数据源配置方式

    2022-10-10 06:47:05
  • Java内存模型中的虚拟机栈原理分析

    2022-02-08 04:41:33
  • springboot 如何解决static调用service为null

    2022-09-05 05:30:03
  • 深入理解Spring事务原理

    2022-01-18 04:16:39
  • MyBatis多表关联查询的实现示例

    2023-07-06 06:26:49
  • 使用logback屏蔽一些包的日志

    2023-08-08 20:46:20
  • C#异步委托调用实例分析

    2022-12-14 05:41:06
  • Springboot jpa @Column命名大小写问题及解决

    2023-02-19 03:24:21
  • C#转换日期类型实例

    2023-07-16 21:01:19
  • 关于Mybatis-Plus Update更新策略问题

    2022-04-14 19:29:24
  • C#中面向对象编程机制之多态学习笔记

    2023-12-06 20:16:33
  • idea创建maven父子工程导致子工程无法导入父工程依赖

    2021-09-17 09:34:08
  • Android编程之交互对话框实例浅析

    2021-09-09 04:47:08
  • JVM类加载机制原理及用法解析

    2021-08-17 00:22:29
  • java判断三位数的实例讲解

    2023-07-06 08:29:53
  • c# 编写的简单飞行棋游戏

    2022-12-05 05:10:59
  • spring中使用@Autowired注解无法注入的情况及解决

    2023-06-10 21:48:24
  • 详解JAVA Spring 中的事件机制

    2022-01-13 05:26:33
  • SpringCloud Eureka服务治理之服务注册服务发现

    2021-12-27 15:07:16
  • asp之家 软件编程 m.aspxhome.com