外国网站加速器,公司logo设计案例,定制衣服的软件app,兰州seo公司1前言
日常开发中#xff0c;难免遇到一些并发的场景#xff0c;为了保证接口执行的一致性#xff0c;通常采用加锁的方式#xff0c;因为服务是分布式部署模式#xff0c;本地锁Reentrantlock和Synchnorized这些就先放到一边了#xff0c;Redis的setnx锁存在无法抱保证…1前言
日常开发中难免遇到一些并发的场景为了保证接口执行的一致性通常采用加锁的方式因为服务是分布式部署模式本地锁Reentrantlock和Synchnorized这些就先放到一边了Redis的setnx锁存在无法抱保证原子性的问题就暂时搁且到一边直接上大招Redisson也是我最近开发项目中基本都在用的缓存并且也都是用它的分布式锁机制。
2Redisson分布式锁常规使用
关于Redisson的一些基本概念本章就不做太详细的说明了有兴趣的小伙伴可以自己去了解下主要说下加锁的常规使用Redisson分布式锁是基于Redis的Rlock锁实现了JavaJUC包下的Lock接口。
Lock
public void getLock(){//获取锁RLock lock redisson.getLock(Lxlxxx_Lock);try {// 2.加锁lock.lock();} catch (InterruptedException e) {e.getStackTrace();} finally {// 3.解锁lock.unlock();System.out.println(Finally释放锁成功);}
getLock获取锁lock.lock进行加锁会出现的问题就是lock拿不到锁一直等待会进入阻塞状态显然这样是不好的。
TryLock
返回boolean类型和Reentrantlock的tryLock是一个意思尝试获取锁获取到就返回true RLock lock redisson.getLock(name);
try {if (lock.tryLock(2, 10, TimeUnit.SECONDS)) {//执行业务逻辑} else {System.out.println(已存在);}
} catch (InterruptedException e) {e.printStackTrace();
}finally {
//判断当前线程持有的锁是不是处于锁定状态锁定状态再进行释放if (this.redissonLock.isHeldByCurrentThread(lockName)) {this.redissonLock.unlock(lockName);}
}
3自定义注解实现锁机制
通常我们都会将redisson实例注入到方法类里面然后调用加锁方法进行加锁如果其他业务方法也需要加锁执行将会产生很多重复代码由此采用AOP切面的方式只需要通过注解的方式就能将方法进行加锁处理。另外搜索公众号Linux就该这样学后台回复“猴子”获取一份惊喜礼包。
自定义注解
Documented
Inherited
Retention(RetentionPolicy.RUNTIME)
Target({ElementType.METHOD})
public interface DistributedLock {String key() default ;int leaseTime() default 10;boolean autoRelease() default true;String errorDesc() default 系统正常处理请稍后提交;int waitTime() default 1;
}
切面类实现
Aspect
Component
public class DistributedLockHandler {private static final Logger log LoggerFactory.getLogger(DistributedLockHandler.class);AutowiredRedissonLock redissonLock;public DistributedLockHandler() {}Around(annotation(distributedLock))public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {String lockName this.getRedisKey(joinPoint, distributedLock);int leaseTime distributedLock.leaseTime();String errorDesc distributedLock.errorDesc();int waitTime distributedLock.waitTime();Object var8;try {boolean lock this.redissonLock.tryLock(lockName, (long)leaseTime, (long)waitTime);if (!lock) {throw new RuntimeException(errorDesc);}var8 joinPoint.proceed();} catch (Throwable var12) {log.error(执行业务方法异常, var12);throw var12;} finally {if (this.redissonLock.isHeldByCurrentThread(lockName)) {this.redissonLock.unlock(lockName);}}return var8;}/*** 获取加锁的key* param joinPoint* param distributedLock* return*/private String getRedisKey(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {String key distributedLock.key();Object[] parameterValues joinPoint.getArgs();MethodSignature signature (MethodSignature)joinPoint.getSignature();Method method signature.getMethod();DefaultParameterNameDiscoverer nameDiscoverer new DefaultParameterNameDiscoverer();String[] parameterNames nameDiscoverer.getParameterNames(method);if (StringUtils.isEmpty(key)) {if (parameterNames ! null parameterNames.length 0) {StringBuffer sb new StringBuffer();int i 0;for(int len parameterNames.length; i len; i) {sb.append(parameterNames[i]).append( ).append(parameterValues[i]);}key sb.toString();} else {key redissionLock;}return key;} else {SpelExpressionParser parser new SpelExpressionParser();Expression expression parser.parseExpression(key);if (parameterNames ! null parameterNames.length ! 0) {EvaluationContext evaluationContext new StandardEvaluationContext();for(int i 0; i parameterNames.length; i) {evaluationContext.setVariable(parameterNames[i], parameterValues[i]);}try {Object expressionValue expression.getValue(evaluationContext);return expressionValue ! null !.equals(expressionValue.toString()) ? expressionValue.toString() : key;} catch (Exception var13) {return key;}} else {return key;}}}
}
具体使用 方法头加自定义注解key参数代表需要加锁的keyerrorDesc获取锁失败提示报错信息。
这边我将项目通过修改端口启动了两个服务分别是8460和8461 通过postman调用这两个服务模拟两个服务同时获取一把锁的场景其中一个服务拿到锁 可以看到端口8460服务先拿到锁8461服务tryLock获取锁失败实现了加锁逻辑 分布式锁的使用场景还是需要多注意下根据业务场景来并发量不大的情况下其实没有