Skip to content

Redisson注解锁

使用

调用方式使用

java
    public void lockFunction() throws InterruptedException {
        redissonLockService.executeWithLock("lockKey",3,TimeUnit.SECONDS, () -> {
            // 执行业务逻辑
            log.info("获取到分布式锁,开始执行业务逻辑");
            return null;
        });
    }

注解方式使用

java
    @RedissonLock(key = "lockKey", prefixKey = "lockPrefix", waitTime = 3)
    public void lockFunction() throws InterruptedException {
        log.info("获取到分布式锁,开始执行业务逻辑");
    }

代码

注解

java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RedissonLock {
    /**
     * key的前缀,默认取方法全限定名
     *
     * @return key的前缀
     */
    String prefixKey() default "";

    /**
     * springEl 表达式
     *
     * @return 表达式
     */
    String [] key();

    /**
     * 获取锁的等待时间,单位秒
     */
    int waitTime() default -1;

}

AOP

java
@Slf4j
@AllArgsConstructor
@Aspect
@Order(0) // 确保分布式锁最先执行
@Component
public class RedissonLockAspect {

    private final RedissonLockService redissonLockService;


    @Around("@annotation(com.ruoyi.common.annotation.RedissonLock)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        log.info("进入分布式锁AOP处理方法: {}", point.getSignature().toShortString());
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        // 获取注解信息
        RedissonLock methodAnnotation = method.getAnnotation(RedissonLock.class);
        // 获取前缀
        String prefixKey = methodAnnotation.prefixKey();
        // 获取key
        String[] keys = methodAnnotation.key();
        // el 解析
        ExpressionParser parser = new SpelExpressionParser(); // el解析器
        DefaultParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer(); // 参数名解析器
        StandardEvaluationContext context = new StandardEvaluationContext(); // el解析需要的上下文对象
        String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
        // 参数添加到上下文
        if (parameterNames != null) {
            for (int i = 0; i < parameterNames.length; i++) {
                context.setVariable(parameterNames[i], point.getArgs()[i]);
            }
        }
        // 解析每个key
        String key = Arrays.stream(keys).map(k -> {
                    Expression expression = parser.parseExpression(k);
                    return expression.getValue(context, String.class);
                })
                .filter(Objects::nonNull)
                .collect(Collectors.joining("_", prefixKey+"_", ""));

        // 获取等待时间和过期时间
        int waitTime = methodAnnotation.waitTime();
        return redissonLockService.executeWithLock(key, waitTime, TimeUnit.SECONDS, () -> {
            try {
                // 执行目标方法
                return point.proceed();
            } catch (Throwable throwable) {
                // 如果有异常,抛出运行时异常
                log.error("执行方法时发生异常: {}", throwable);
                throw new ServiceException("执行方法时发生异常: " + throwable.getMessage());
            }
        });
    }
}

锁实现

java
@Slf4j
@Service
@AllArgsConstructor
public class RedissonLockService {


    private final Redisson redisson;


    /**
     * 默认分布式锁等待时间 10秒
     */
    private static final  int LOCK_DEFAULT_WAIT_TIME =10 ;

    /**
     * 执行带分布式锁的操作 默认等待时间为10秒
     * @param key 分布式锁的唯一标识
     * @param supplier 执行的操作,返回结果
     * @return
     */
    public  <T> T executeWithLock(String key, Supplier<T> supplier) throws InterruptedException,ServiceException {
        return executeWithLock(key, LOCK_DEFAULT_WAIT_TIME, TimeUnit.SECONDS, supplier);
    }

    /**
     * 执行带分布式锁的操作
     * @param key 分布式锁的唯一标识
     * @param waitTime 获取锁的等待时间
     * @param timeUnit 获取锁的时间单位
     * @param supplier 执行的操作,返回结果
     */
    public <T> T executeWithLock(String key, Integer waitTime, TimeUnit timeUnit, Supplier<T> supplier) throws InterruptedException, ServiceException {
        // 尝试获取锁
        RLock lock = redisson.getLock(key);
        boolean tryLock = lock.tryLock(waitTime, timeUnit);
        if (!tryLock) {
            throw new ServiceException("获取分布式锁失败");
        }
        try {
           return  supplier.get();
        } finally {
            // 确保释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


}
最近更新