All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.kqinfo.universal.redis.aspect.RedisLockAspect Maven / Gradle / Ivy

package com.kqinfo.universal.redis.aspect;

import com.kqinfo.universal.redis.annotation.RedisLock;
import com.kqinfo.universal.redis.enums.LockStrategy;
import com.kqinfo.universal.redis.exception.RedisLockException;
import com.kqinfo.universal.redis.lock.LockFactory;
import com.kqinfo.universal.redis.properties.KqRedisProperties;
import com.kqinfo.universal.redis.util.LockContext;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * redis lock 切面
 *
 * @author Zijian Liao
 * @since 1.0.0
 */
@Aspect
public class RedisLockAspect {

    private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    @Resource
    private RedissonClient redissonClient;
    @Resource
    private KqRedisProperties redisProperties;

    @Around(value = "@annotation(redisLock)")
    public Object lock(ProceedingJoinPoint joinPoint, RedisLock redisLock) throws Throwable {
        // 拼接出key
        String key = getRedisKey(joinPoint, redisLock);
        // 获取锁
        RLock lock = LockFactory.createLock(redissonClient, redisLock.lockType(), key);
        try {
            // 根据策略加锁
            redisLock.lockStrategy().lock(lock, redisLock);
            // 兼容不抛出异常逻辑
            if(LockStrategy.SKIP_AND_RETURN_NULL == redisLock.lockStrategy()){
                Boolean locked = LockContext.getAndRemove();
                // locked为null, 表示加锁失败,直接返回null
                if(locked == null){
                    return null;
                }
            }
            return joinPoint.proceed();
        }finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private String getRedisKey(ProceedingJoinPoint joinPoint, RedisLock redisLock){
        EvaluationContext context = new MethodBasedEvaluationContext(TypedValue.NULL, resolveMethod(joinPoint), joinPoint.getArgs(), parameterNameDiscoverer);
        StringBuilder sb = new StringBuilder();
        sb.append(redisProperties.getPrefix()).append(redisLock.name());
        ExpressionParser parser = new SpelExpressionParser();
        for (String key : redisLock.keys()) {
            // keys是个spel表达式
            Expression expression = parser.parseExpression(key);
            Object value = expression.getValue(context);
            sb.append(ObjectUtils.nullSafeToString(value));
        }
        return sb.toString();
    }

    private Method resolveMethod(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Class targetClass = joinPoint.getTarget().getClass();

        return getDeclaredMethodFor(targetClass, signature.getName(),
                signature.getMethod().getParameterTypes());
    }

    private Method getDeclaredMethodFor(Class clazz, String name, Class... parameterTypes) {
        try {
            return clazz.getDeclaredMethod(name, parameterTypes);
        } catch (NoSuchMethodException e) {
            Class superClass = clazz.getSuperclass();
            if (superClass != null) {
                return getDeclaredMethodFor(superClass, name, parameterTypes);
            }
        }
        throw new IllegalStateException("Cannot resolve target method: " + name);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy