这篇文章主要讲解了“如何使用自定义注解实现redisson分布式锁”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用自定义注解实现redisson分布式锁”吧!
自定义注解实现redisson分布式锁
自定义注解
package com.example.demo.annotation;import java.lang.annotation.*;@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface Lock { String key(); long keepMills() default 20; 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;@Aspect@Componentpublic class LockAspect { @Autowired private RedissonClient redissonClient; 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; } 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中使用注解加锁使用
@Servicepublic class LockService { @Lock(key = "#user.id", keepMills = 10, maxSleepMills = 15) public String lock(User user) { System.out.println("持锁"); return ""; }}
redisson分布式锁应用
分布式架构一定会用到分布式锁。目前公司使用的基于redis的redisson分布式锁。
应用场景
订单修改操作,首先要获取该订单的分布式锁,能取到才能去操作。lockey可以是订单的主键id。
库存操作,也要按照客户+仓库+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); } 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() + "获得了锁"); 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的一个线程能获取到锁。
感谢各位的阅读,以上就是“如何使用自定义注解实现redisson分布式锁”的内容了,经过本文的学习后,相信大家对如何使用自定义注解实现redisson分布式锁这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!