千家信息网

spring boot redis分布式锁

发表于:2025-01-25 作者:千家信息网编辑
千家信息网最后更新 2025年01月25日,spring boot redis分布式锁参照spring boot redis分布式锁 用注解实现时发现不能满足使用需求于是自己开始摸索解决问题...如下,value 是lock的key,因为业务的
千家信息网最后更新 2025年01月25日spring boot redis分布式锁

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().parse_Expression(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


0