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

网友投稿 445 2022-08-27


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

目录自定义注解实现redisson分布式锁自定义注解aop解析注解service中使用注解加锁使用redisson分布式锁应用应用场景Redisson管理类分布式锁测试类

自定义注解实现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) {

MethTppzRVhodSignature 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 Dhttp://istributedLock {

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的一个线程能获取到锁。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:python读写ini格式的配置文件(python init文件怎么写)
下一篇:python执行系统命令(python执行系统命令时无法显示中文)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~