redis注解锁
注解 :@DistributeLock
/**
* @author:syh
* @date:2023/8/21
* 描述: redisson RLock 注解分布锁
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DistributeLock {
/**
* redis锁 名字
*/
String lockName() default "";
/**
* redis锁 key 支持spel表达式
*/
String key() default "";
/**
* 等待时间,默认为0毫秒
*
* @return 轮询锁的时间
*/
int waitTime() default 0;
/**
* 过期秒数,默认使用watchDog
*
* @return 轮询锁的时间
*/
int expireTime() default -1;
/**
* 超时时间单位
*
* @return 毫秒
*/
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
/**
* 报错信息
*
* @return
*/
String errorMsg() default "";
}
spel解析
/**
* @author:syh
* @date:2023/8/21
* 描述: redisson RLock spel解析 注解分布锁
**/
public class SpelUtil {
/**
* 支持 #p0 参数索引的表达式解析
*
* @param rootObject 根对象,method 所在的对象
* @param spel 表达式
* @param method ,目标方法
* @param args 方法入参
* @return 解析后的字符串
*/
public static String parse(Object rootObject, String spel, Method method, Object[] args) {
if (StrUtil.isBlank(spel)) {
return StrUtil.EMPTY;
}
//获取被拦截方法参数名列表(使用Spring支持类库)
LocalVariableTableParameterNameDiscoverer u =
new LocalVariableTableParameterNameDiscoverer();
String[] paraNameArr = u.getParameterNames(method);
if (ArrayUtil.isEmpty(paraNameArr)) {
return spel;
}
//使用SPEL进行key的解析
ExpressionParser parser = new SpelExpressionParser();
//SPEL上下文
StandardEvaluationContext context = new MethodBasedEvaluationContext(rootObject, method, args, u);
//把方法参数放入SPEL上下文中
for (int i = 0; i < paraNameArr.length; i++) {
context.setVariable(paraNameArr[i], args[i]);
}
return parser.parseExpression(spel).getValue(context, String.class);
}
}
aspect 环绕
/**
* @author:syh
* @date:2023/8/21
* 描述: redisson RLock 注解分布锁
**/
@Aspect
@Component
public class DistributeLockAspect {
private static final Logger LOG = LoggerFactory.getLogger(DistributeLockAspect.class);
@Autowired
private RedissonClient redissonClient;
private static final String REDISSON_LOCK_PREFIX = "redis:syh:lock:";
@Around("@annotation(distributeLock)")
public Object around(ProceedingJoinPoint joinPoint, DistributeLock distributeLock) throws Throwable {
String spel = distributeLock.key();
String lockName = distributeLock.lockName();
String errorMsg = distributeLock.errorMsg();
String lockKey = getRedisKey(joinPoint, lockName, spel);
RLock rLock = redissonClient.getLock(lockKey);
Object result = null;
boolean res = rLock.tryLock(distributeLock.waitTime(), distributeLock.expireTime(), distributeLock.timeUnit());
if (!res) {
LOG.info("aspectLock_key:{}获取锁失败", lockKey);
if (StringUtils.isNotBlank(errorMsg)) {
throw new BizException(errorMsg);
}
return result;
}
try {
LOG.info("aspectLock_key:{}获取锁成功", lockKey);
//执行方法
result = joinPoint.proceed();
} finally {
LOG.info("aspectLock_key:{}释放锁成功", lockKey);
rLock.unlock();
}
return result;
}
/**
* 将spel表达式转换为字符串
*
* @param joinPoint 切点
* @return redisKey
*/
private String getRedisKey(ProceedingJoinPoint joinPoint, String lockName, String spel) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method targetMethod = methodSignature.getMethod();
Object target = joinPoint.getTarget();
Object[] arguments = joinPoint.getArgs();
String key = REDISSON_LOCK_PREFIX + lockName + StrUtil.COLON + SpelUtil.parse(target, spel, targetMethod, arguments);
return key;
}
}