package org.jeecg.boot.starter.lock.aspect;
|
|
import lombok.SneakyThrows;
|
import lombok.extern.slf4j.Slf4j;
|
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.jeecg.boot.starter.lock.annotation.JLock;
|
import org.jeecg.boot.starter.lock.enums.LockModel;
|
import org.redisson.RedissonMultiLock;
|
import org.redisson.RedissonRedLock;
|
import org.redisson.api.RLock;
|
import org.redisson.api.RedissonClient;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
import org.springframework.expression.EvaluationContext;
|
import org.springframework.expression.Expression;
|
import org.springframework.expression.ExpressionParser;
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
import org.springframework.stereotype.Component;
|
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.concurrent.TimeUnit;
|
|
|
/**
|
* 分布式锁解析器
|
*
|
* @author zyf
|
* @date 2020-11-11
|
*/
|
@Slf4j
|
@Aspect
|
@Component
|
public class DistributedLockHandler extends BaseAspect{
|
|
|
@Autowired(required = false)
|
private RedissonClient redissonClient;
|
|
/**
|
* 切面环绕通知
|
*
|
* @param joinPoint
|
* @param jLock
|
* @return Object
|
*/
|
@SneakyThrows
|
@Around("@annotation(jLock)")
|
public Object around(ProceedingJoinPoint joinPoint, JLock jLock) {
|
Object obj = null;
|
log.info("进入RedisLock环绕通知...");
|
RLock rLock = getLock(joinPoint, jLock);
|
boolean res = false;
|
//获取超时时间
|
long expireSeconds = jLock.expireSeconds();
|
//等待多久,n秒内获取不到锁,则直接返回
|
long waitTime = jLock.waitTime();
|
//执行aop
|
if (rLock != null) {
|
try {
|
if (waitTime == -1) {
|
res = true;
|
//一直等待加锁
|
rLock.lock(expireSeconds, TimeUnit.MILLISECONDS);
|
} else {
|
res = rLock.tryLock(waitTime, expireSeconds, TimeUnit.MILLISECONDS);
|
}
|
if (res) {
|
obj = joinPoint.proceed();
|
} else {
|
log.error("获取锁异常");
|
}
|
} finally {
|
if (res) {
|
rLock.unlock();
|
}
|
}
|
}
|
log.info("结束RedisLock环绕通知...");
|
return obj;
|
}
|
|
@SneakyThrows
|
private RLock getLock(ProceedingJoinPoint joinPoint, JLock jLock) {
|
String[] keys = jLock.lockKey();
|
if (keys.length == 0) {
|
throw new RuntimeException("keys不能为空");
|
}
|
String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(((MethodSignature) joinPoint.getSignature()).getMethod());
|
Object[] args = joinPoint.getArgs();
|
|
LockModel lockModel = jLock.lockModel();
|
if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.REDLOCK) && keys.length > 1) {
|
throw new RuntimeException("参数有多个,锁模式为->" + lockModel.name() + ".无法锁定");
|
}
|
RLock rLock = null;
|
String keyConstant = jLock.keyConstant();
|
if (lockModel.equals(LockModel.AUTO)) {
|
if (keys.length > 1) {
|
lockModel = LockModel.REDLOCK;
|
} else {
|
lockModel = LockModel.REENTRANT;
|
}
|
}
|
switch (lockModel) {
|
case FAIR:
|
rLock = redissonClient.getFairLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0));
|
break;
|
case REDLOCK:
|
List<RLock> rLocks = new ArrayList<>();
|
for (String key : keys) {
|
List<String> valueBySpEL = getValueBySpEL(key, parameterNames, args, keyConstant);
|
for (String s : valueBySpEL) {
|
rLocks.add(redissonClient.getLock(s));
|
}
|
}
|
RLock[] locks = new RLock[rLocks.size()];
|
int index = 0;
|
for (RLock r : rLocks) {
|
locks[index++] = r;
|
}
|
rLock = new RedissonRedLock(locks);
|
break;
|
case MULTIPLE:
|
rLocks = new ArrayList<>();
|
|
for (String key : keys) {
|
List<String> valueBySpEL = getValueBySpEL(key, parameterNames, args, keyConstant);
|
for (String s : valueBySpEL) {
|
rLocks.add(redissonClient.getLock(s));
|
}
|
}
|
locks = new RLock[rLocks.size()];
|
index = 0;
|
for (RLock r : rLocks) {
|
locks[index++] = r;
|
}
|
rLock = new RedissonMultiLock(locks);
|
break;
|
case REENTRANT:
|
List<String> valueBySpEL = getValueBySpEL(keys[0], parameterNames, args, keyConstant);
|
//如果spel表达式是数组或者LIST 则使用红锁
|
if (valueBySpEL.size() == 1) {
|
rLock = redissonClient.getLock(valueBySpEL.get(0));
|
} else {
|
locks = new RLock[valueBySpEL.size()];
|
index = 0;
|
for (String s : valueBySpEL) {
|
locks[index++] = redissonClient.getLock(s);
|
}
|
rLock = new RedissonRedLock(locks);
|
}
|
break;
|
case READ:
|
rLock = redissonClient.getReadWriteLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0)).readLock();
|
break;
|
case WRITE:
|
rLock = redissonClient.getReadWriteLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0)).writeLock();
|
break;
|
}
|
return rLock;
|
}
|
}
|