spring boot redis分布式锁
参照spring boot redis分布式锁 用注解实现时发现不能满足使用需求
于是自己开始摸索解决问题...
如下,value 是lock的key,因为业务的需要key是 "cancelOrder_123_321" 123是订单ID,321是用户ID
@RedisLock(value = "cancelOrder_#{#order.orderNo}_#{#memberId}")
@Transactional(rollbackFor = {RuntimeException.class, Exception.class})
public void cancelOrder(Order order, String memberId) {
log.info("用户:{},订单号:{} 开始执行取消流程...",order.getOrderNo(),memberId);
String orderNo = order.getOrderNo();
Order updateOrder = new Order();
updateOrder.setOrderNo(orderNo);
updateOrder.setOrderState(OrderStateEnum.CANCELED.getKey());
长话短说,需要了解详情的朋友看其他大神的博客
为什么我可以这样 cancelOrder_#{#order.orderNo}_#{#memberId} 写?
这里最重要的是什么?
是因为我将这个el表达式字符串,解析成了复合型了.复合型简单点就是List集合,集合里有el表达式和文本,用for顺序执行.
代码如下:
Aspect类
private static final OperationExpressionEvaluator evaluator = new OperationExpressionEvaluator();
@Around("lockPoint()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
Method method = ((MethodSignature)pjp.getSignature()).getMethod();
RedisLock redisLock = method.getAnnotation(RedisLock.class);
String key = getKey(redisLock.value(),method,pjp.getArgs(),pjp.getTarget());
int retryTimes = redisLock.action().equals(RedisLock.LockFailAction.CONTINUE) ? redisLock.retryTimes() : 0;
boolean lock = redisLockImpl.lock(key,redisLock.keepMills(),retryTimes,redisLock.sleepMills());
if(!lock){
log.debug("get lock failed:{}",key);
return null;
}
log.debug("get lock success:{}",key);
try{
return pjp.proceed();
}catch (Exception e){
log.error("execute locked method occured an exception",e);
} finally {
boolean releaseResult = redisLockImpl.releaseLock(key);
log.debug("release lock:{}-{}",key,releaseResult ? "success":"failed");
}
return null;
}
private String getKey(String key,Method method,Object [] args,Object target){
if(key.length() <= 0){
return Arrays.toString(args);
}
return String.valueOf(generateKey(key,method,args,target));
}
private Object generateKey(String key,Method method,Object [] args,Object target) {
EvaluationContext evaluationContext = evaluator.createEvaluationContext(method, args, target, target.getClass(), null);
return evaluator.key(key, evaluationContext);
}
OperationExpressionEvaluator 类
/**
* @author liuhanling
* @create 2019-01-14 17:03
* @desc 操作表达式评估器
*/
public class OperationExpressionEvaluator extends CachedExpressionEvaluator{
private final ParserContext parserContext = new ParserContext() {
@Override
public boolean isTemplate() {
return true;
}
@Override
public String getExpressionPrefix() {
return "#{";
}
@Override
public String getExpressionSuffix() {
return "}";
}
};
/**
* Create an {@link EvaluationContext}.
* @param method the method
* @param args the method arguments
* @param target the target object
* @param targetClass the target class
* @return the evaluation context
*/
public EvaluationContext createEvaluationContext(Method method, Object[] args, Object target, Class<?> targetClass, BeanFactory beanFactory) {
//bean context
ExpressionRootObject rootObject = new ExpressionRootObject(method, args, target, targetClass);
//获取目标方法
Method targetMethod = getTargetMethod(targetClass, method);
//评测上下文,主要是处理无用变量
MethodBasedEvaluationContext evaluationContext = new MethodBasedEvaluationContext(rootObject,targetMethod,args,getParameterNameDiscoverer());
//CacheEvaluationContext evaluationContext = new CacheEvaluationContext(rootObject, targetMethod, args, getParameterNameDiscoverer());
if (beanFactory != null) {
evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
}
return evaluationContext;
}
public Object key(String keyExpression, EvaluationContext evalContext) {
//执行el表达式 复合型
return getParser().parseExpression(keyExpression,parserContext).getValue(evalContext);
}
private Method getTargetMethod(Class<?> targetClass, Method method) {
//AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass);
//Method targetMethod = this.targetMethodCache.get(methodKey);
//if (targetMethod == null) {
Method targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
if (targetMethod == null) {
targetMethod = method;
}
//this.targetMethodCache.put(methodKey, targetMethod);
//}
return targetMethod;
}
}
ExpressionRootObject 类
/**
* @author liuhanling
* @create 2019-01-14 17:04
* @desc 表达式 rootObject
*/
public class ExpressionRootObject {
/**
* 方法
*/
private final Method method;
/**
* 参数数组
*/
private final Object[] args;
/**
* 目标对象
*/
private final Object target;
/**
* 目标类
*/
private final Class<?> targetClass;
public ExpressionRootObject(Method method, Object[] args, Object target, Class<?> targetClass) {
Assert.notNull(method, "Method is required");
Assert.notNull(targetClass, "targetClass is required");
this.method = method;
this.target = target;
this.targetClass = targetClass;
this.args = args;
}
public Method getMethod() {
return this.method;
}
public String getMethodName() {
return this.method.getName();
}
public Object[] getArgs() {
return this.args;
}
public Object getTarget() {
return this.target;
}
public Class<?> getTargetClass() {
return this.targetClass;
}
}
[1]参考链接(spring boot redis分布式锁) https://my.oschina.net/dengfuwei/blog/1600681
[2]参考链接(el表达式) https://blog.csdn.net/zhoudaxia/article/details/38174169
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。