@RedisLock(lockName = "device_goods_stock",key="'skuId:'+#skuId" , expire = 2000)
/*
* Copyright (c) 2018-2999 广州亚米信息科技有限公司 All rights reserved.
*
* https://www.gz-yami.com/
*
* 未经允许,不可做商业用途!
*
* 版权所有,侵权必究!
*/
package com.box.lock.annotation;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* 使用redis进行分布式锁
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisLock {
/**
* redis锁 名字
*/
String lockName() default "";
/**
* redis锁 key 支持spel表达式
*/
String key() default "";
/**
* 过期秒数,默认为5毫秒
*
* @return 轮询锁的时间
*/
int expire() default 5000;
/**
* 超时时间单位
*
* @return 毫秒
*/
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
/*
* Copyright (c) 2018-2999 广州亚米信息科技有限公司 All rights reserved.
*
* https://www.gz-yami.com/
*
* 未经允许,不可做商业用途!
*
* 版权所有,侵权必究!
*/
package com.box.lock.aspect;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.box.lock.annotation.RedisLock;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
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.lang.reflect.Method;
/**
* @author yuandingwang
*/
@Aspect
@Component
public class RedisLockAspect {
@Autowired
private RedissonClient redissonClient;
private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";
@Around("@annotation(redisLock)")
public Object around(ProceedingJoinPoint joinPoint, RedisLock redisLock) throws Throwable {
String spel = redisLock.key();
String lockName = redisLock.lockName();
RLock rLock = redissonClient.getLock(getRedisKey(joinPoint, lockName, spel));
rLock.lock(redisLock.expire(), redisLock.timeUnit());
Object result = null;
try {
//执行方法
result = joinPoint.proceed();
// System.out.println("分布式锁");
} finally {
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();
return REDISSON_LOCK_PREFIX + lockName + StrUtil.COLON + parse(target, spel, targetMethod, arguments);
}
private static String parse(Object rootObject,String spel, Method method, Object[] args) {
if (StringUtils.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);
}
}
}