分布式锁注解DistributedRedisLockAspect

package com.data.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
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 javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.UUID;


@Slf4j
@Component
@Aspect
public class DistributedRedisLockAspect {

    private static final ThreadLocal<String> LOCK_VALUE = ThreadLocal.withInitial(() -> UUID.randomUUID().toString());
    private static final String FORMAT = "%s:%s";
    @Resource
    Lock lock;

    /**
     * SpEL 解析器
     */
    private ExpressionParser parser = new SpelExpressionParser();
    /**
     * 用于获取参数名
     */
    private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();

    @Around("@annotation(com.data.DistributedRedisLock)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result;
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Object[] args = point.getArgs();
        DistributedRedisLock redisLockAnnotation = method.getAnnotation(DistributedRedisLock.class);
        // key 前缀
        String preKey = redisLockAnnotation.preKey();
        String key = redisLockAnnotation.key();
        long timeout = redisLockAnnotation.timeout();
        // 生成缓存 Key
        String cacheKey = this.generatorKey(preKey, key, method, args);
        // 生成当前锁的唯一标识
        String value = LOCK_VALUE.get();
        lock.lock(cacheKey, value, timeout);
        try {
            result = point.proceed();
        } finally {
            // 只有 key value 完全匹配才能解锁
            lock.unlock(cacheKey, value);
        }
        return result;
    }

    private String generatorKey(String pre, String key, Method method, Object[] args) {
        //获取方法参数名
        String[] params = discoverer.getParameterNames(method);
        //将参数纳入Spring管理
        EvaluationContext context = new StandardEvaluationContext();
        for (int len = 0; len < params.length; len++) {
            context.setVariable(params[len], args[len]);
        }
        Expression expression = parser.parseExpression(key);
        String spelValue = expression.getValue(context, String.class);
        return String.format(FORMAT, pre, spelValue);
    }

}

 

posted @ 2025-04-30 15:44  甜菜波波  阅读(28)  评论(0)    收藏  举报