十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
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