分布式锁注解模板

78 阅读1分钟

使用Redission实现优雅的分布式锁的使用

定义注解

public @interface DistributeLock {

    /**
     * 锁的场景
     */
    public String scene() default DistributeLockConstant.DEFAULT_SCENE;

    /**
     * 加锁的key,优先取key(),如果没有,则取keyExpression()
     */
    public String key() default DistributeLockConstant.NONE_KEY;

    /**
     * SPEL表达式:
     */
    public String keyExpression() default DistributeLockConstant.NONE_KEY;

    /**
     * 超时时间,毫秒
     * 默认情况下不设置超时时间,会自动续期
     */
    public int expireTime() default DistributeLockConstant.DEFAULT_EXPIRE_TIME;

    /**
     * 加锁等待时长,毫秒
     * 默认情况下不设置等待时长,不做等待
     */
    public int waitTime() default DistributeLockConstant.DEFAULT_WAIT_TIME;
}

实现一个utils去解析SPEL

public class SPelUtil {

    private static final ExpressionParser parser = new SpelExpressionParser();
    private static final StandardReflectionParameterNameDiscoverer parameterNameDiscoverer = new StandardReflectionParameterNameDiscoverer();

    public static String parseSpEl(Method method, Object[] args, String spEl) {
        String[] params = Optional.ofNullable(parameterNameDiscoverer.getParameterNames(method)).orElse(new String[]{});//解析参数名
        EvaluationContext context = new StandardEvaluationContext();//el解析需要的上下文对象
        for (int i = 0; i < params.length; i++) {
            context.setVariable(params[i], args[i]);//所有参数都作为原材料扔进去
        }
        Expression expression = parser.parseExpression(spEl);
        return expression.getValue(context, String.class);
    }


    public static String getLockKey(String perFix , String key){
        return perFix + key;
    }
}

实现切面逻辑

@Aspect
@Component
public class DistributeLockAspect {

    private RedissonClient redissonClient;

    public DistributeLockAspect(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    private static final Logger LOG = LoggerFactory.getLogger(DistributeLockAspect.class);

    @Around("@annotation(DistributeLock)")
    public Object process(ProceedingJoinPoint pjp) throws Exception {
        Object response = null;
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        DistributeLock distributeLock = method.getAnnotation(DistributeLock.class);

        String key = distributeLock.key();
        if (DistributeLockConstant.NONE_KEY.equals(key)) {
            if (DistributeLockConstant.NONE_KEY.equals(distributeLock.keyExpression())) {
                throw new DistributeLockException("no lock key found...");
            }
            // 获取参数值
            Object[] args = pjp.getArgs();

            key = SPelUtil.parseSpEl(method, args, distributeLock.keyExpression());
        }
        // 默认取方法名称作为分布式锁的key
        String scene = Optional.ofNullable(distributeLock.scene()).orElse(method.getName());

        String lockKey = scene + "#" + key;

        int expireTime = distributeLock.expireTime();
        int waitTime = distributeLock.waitTime();
        RLock rLock = redissonClient.getLock(lockKey);
        boolean lockResult = lockResult = rLock.tryLock(waitTime, expireTime, TimeUnit.MILLISECONDS);;
        if (!lockResult) {
            LOG.warn(String.format("lock failed for key : %s , expire : %s", lockKey, expireTime));
            throw new DistributeLockException("acquire lock failed... key : " + lockKey);
        }
        try {
            LOG.info(String.format("lock success for key : %s , expire : %s", lockKey, expireTime));
            response = pjp.proceed();
        } catch (Throwable e) {
            throw new Exception(e);
        } finally {
            rLock.unlock();
            LOG.info(String.format("unlock for key : %s , expire : %s", lockKey, expireTime));
        }
        return response;
    }
}