Redisson分布式锁实战+AOP

本文介绍如何在Spring Boot应用中使用Redisson实现分布式锁,并通过自定义注解@DistributeLock配合AOP,简化方法级别的锁控制。只需在方法上添加注解,即可自动进行锁的获取与释放,实现实例并发控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redisson分布式锁实战+AOP

前言

在实现分布式锁得基础上,利用自定义注解+AOP实现参数级别上的分布式锁。只需要在方法上加上自定义的注解即可,还可选择锁定参数,比较方便

自定义注解@DistributeLock

/**
 * 分布式锁注解,用于方法级别的分布式控制
 *
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributeLock {

    /**
     * 要锁哪几个位置的参数,默认不锁参数
     */
    int[] lockIndex() default {-1};


    /**
     * 等待时间,默认2000毫秒
     */
    int waitTime() default 2000;

    /**
     * 自动失效时间,默认30000毫秒
     */
    int expireTime() default 30000;

    /**
     * 时间类型,默认毫秒
     */
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;

}

对加上了@DistributeLock注解的方法进行@Around增强

/**
 * 方法级别的分布式锁
 *
 * @author : itoyoung
 */
@Component
@Aspect
@Slf4j
public class DistributeLockAspect {

    @Resource
    private RedissonLock redissonLock;

    @Around("@annotation(lock)")
    public Object syncLock(ProceedingJoinPoint joinPoint, DistributeLock lock) {

        Signature signature = joinPoint.getSignature();
        StringBuilder lockKeyBuilder = new StringBuilder(signature.getDeclaringTypeName() + "." + signature.getName());

        Object[] args = joinPoint.getArgs();

        int[] lockIndex = lock.lockIndex();
        if (lockIndex.length > 0 && lockIndex[0] >= 0) {
            for (int index : lockIndex) {
                if (index >= args.length || index < 0) {
                    throw new BaseRuntimeException("参数索引lockIndex: " + index + " 异常");
                }
                lockKeyBuilder.append(".").append(JSON.toJSONString(args[index]));
            }
        }

        // 防止key值太长,用根据其生成的hash值做key
        String lockKey = StringUtil.md5(lockKeyBuilder.toString());
        boolean res = redissonLock.tryLock(lockKey, lock.expireTime(), lock.waitTime(), lock.timeUnit());

        if (res) {
            log.info("AspectLock: key: {} 加锁成功", lockKeyBuilder);
            try {
                return joinPoint.proceed();
            } catch (Throwable e) {
                log.error("AspectLock: key: {} 业务异常", lockKeyBuilder);
                throw new BaseRuntimeException(e.getMessage());
            } finally {
                // 释放锁
                redissonLock.unLock(lockKey);
                log.info("AspectLock: key: {} 释放锁成功", lockKeyBuilder);
            }
        } else {
            log.warn("AspectLock: key: {} 获取锁失败", lockKeyBuilder);
            throw new BaseRuntimeException("异常错误,请稍后重试");
        }
    }

}

实测

@RestController
@Slf4j
@RequestMapping("/test/redissonLock")
public class RedissonLockTestController {

    @Resource
    private ILockCountService lockCountService;

    @Resource
    private ILockStatusService lockStatusService;

    /**
     * 对方法加上分布式锁
     * 
     * @param lockName
     * @param users
     * @return
     */
    @PostMapping("/aspectLock/{lockName}")
    @DistributeLock(lockIndex = {0, 1}, waitTime = 3, expireTime = 30, timeUnit = TimeUnit.SECONDS)
    public Result aspectLock(@PathVariable("lockName") String lockName, @RequestBody List<User> users) {

        LockStatus status = lockStatusService.getById(1);
        if (status.getStatus().equals("N")) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            LockCount count = lockCountService.getOne(new QueryWrapper<LockCount>().lambda().eq(LockCount::getLockId, status.getId()));
            count.setCount(count.getCount() + 1);
            lockCountService.updateById(count);

            status.setStatus("Y");
            lockStatusService.updateById(status);
        }
        return new Result().defaultSuccess();
    }

}

实测五百线程并发访问,count只自增了一次,结果正确
在这里插入图片描述在这里插入图片描述

<think>首先,用户的问题是:“我想了解如何在Redisson分布式锁中添加前缀请问Redisson分布式锁key加前缀实现方法”。这涉及到Redisson分布式锁的使用,具体是如何在key中添加前缀。从系统级指令中,我需要:-所有行内数学表达式使用$...$格式,但这里可能不涉及数学,所以我会注意。-独立公式使用$$...$$格式并单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-在回答中引用的段落末尾自然地添加引用标识,如[^1]。-回答结构清晰,帮助用户逐步解决问题。-参考站内引用:有三个引用提供:-[^1]:关于Redisson实现分布式锁的基本介绍。-[^2]:关于Redis多节点同步问题和redlock。-[^3]:关于使用注解实现分布式锁的示例。用户的问题是关于添加前缀到Redisson分布式锁的key。所以,我需要解释如何在Redisson中为锁key添加前缀。回顾Redisson的使用:-Redisson是一个Java客户端库,用于Redis。-它提供了RLock接口来实现分布式锁。-通常,锁是通过key来标识的。在Redisson中,如何添加前缀?-在创建锁时,key可以是字符串。所以,一个简单的方法是直接在key中包含前缀。-例如,如果前缀是"app:",那么锁key可以是"app:lock_key"。-用户可能想知道是否有内置的方式或最佳实践。从引用[^3]中,有一个注解@DistributedLock,其中包含prefix()属性:-@DistributedLock(prefix="my_prefix",key="lock_key")-这表明在实现中,prefix和key可以组合起来形成完整的锁key。所以,在Redisson中,实现key加前缀的方法:1.手动拼接key:在代码中直接使用带有前缀的字符串作为key。2.使用自定义配置:在Redisson配置中设置key前缀。3.通过注解(如果使用Spring或类似框架):如引用[^3]所示。现在,构建回答:-结构清晰:逐步解释。-先介绍基本概念。-然后给出实现方法。-最后生成相关问题。步骤:1.解释Redisson分布式锁。2.说明key的重要性。3.介绍添加前缀的方法。4.提供代码示例。5.引用相关部分。6.生成相关问题。生成相关问题:-基于主题:分布式锁Redisson、key管理。-例如:1.如何自定义Redisson锁的key生成策略?2.分布式锁key的命名最佳实践是什么?3.Redisson中如何处理锁的过期时间?确保回答真实可靠:基于Redisson文档和常识。</think>### Redisson分布式锁添加前缀的实现方法 在Redisson中,分布式锁通过唯一的key来标识资源。添加前缀到key是一种常见做法,用于避免key冲突、实现命名空间隔离或标识业务场景(例如区分不同服务的锁)。下面我将逐步解释实现方法,确保结构清晰易懂。 #### 步骤1:理解Redisson锁的基本使用 Redisson通过`RLock`接口实现分布式锁。创建锁时,需指定一个字符串key: ```java RLock lock = redissonClient.getLock("my_lock_key"); ``` - 这里的`"my_lock_key"`就是锁的标识符。 - 添加前缀的本质是修改这个key,例如改为`"prefix:my_lock_key"`,其中`prefix`是自定义前缀(如业务模块名或环境标识)[^1]。 #### 步骤2:实现key加前缀的方法 以下是两种常用方法,适用于大多数场景: **方法1:手动拼接前缀(推荐,简单灵活)** 在获取锁时直接拼接字符串作为key: ```java String prefix = "order_service"; // 自定义前缀,例如业务模块名 String lockName = "payment_lock"; // 锁的基础名称 String fullKey = prefix + ":" + lockName; // 组合成完整key RLock lock = redissonClient.getLock(fullKey); try { if (lock.tryLock(10, 30, TimeUnit.SECONDS)) { // 尝试加锁,带超时时间 // 执行业务逻辑 } } finally { lock.unlock(); // 释放锁 } ``` - **优点**:无需额外配置,代码直观,适用于所有Redisson版本。 - **注意事项**:前缀应简洁且唯一,避免使用特殊字符(如空格),以免影响Redis key的解析[^1]。 **方法2:通过注解动态生成前缀(适用于Spring框架)** 如果项目使用Spring,可参考分布式锁注解(如引用[^3]的`@DistributedLock`),自定义前缀逻辑: ```java @DistributedLock(prefix = "inventory_", key = "#itemId") // prefix属性定义前缀,key使用SpEL动态生成 public void updateInventory(String itemId) { // 方法执行时自动生成key,例如"inventory_item123" } ``` - **实现注解的切面逻辑**(简化示例): ```java @Aspect @Component public class DistributedLockAspect { @Autowired private RedissonClient redissonClient; @Around("@annotation(distributedLock)") public Object applyLock(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable { String prefix = distributedLock.prefix(); // 获取注解中的前缀 String dynamicKey = ... // 解析SpEL表达式生成key,例如从方法参数获取 String fullKey = prefix + dynamicKey; RLock lock = redissonClient.getLock(fullKey); try { if (lock.tryLock(distributedLock.waitTime(), distributedLock.leaseTime(), distributedLock.timeUnit())) { return joinPoint.proceed(); // 执行业务方法 } } finally { lock.unlock(); } } } ``` - **优点**:代码解耦,便于统一管理锁策略。 - **缺点**:需额外实现切面逻辑,依赖于Spring AOP[^3]。 #### 关键注意事项 1. **前缀设计原则**: - 使用冒号`:`分隔前缀和key,符合Redis的命名习惯(例如`"service:lock"`)。 - 确保全局唯一性,防止不同服务间的key冲突。 2. **性能影响**:添加前缀不会增加Redis操作开销,因为key比较是O(1)操作[^2]。 3. **分布式环境**:在集群模式下,Redisson通过`RedissonRedLock`(多节点锁)仍支持带前缀的key,但需确保所有节点使用相同前缀策略以避免同步问题[^2]。 通过以上方法,您可以灵活地为Redisson分布式锁添加前缀,提升系统的可维护性和安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值