redisson分布式锁--实际应用!!!

发布于:2025-04-17 ⋅ 阅读:(32) ⋅ 点赞:(0)

我的做法:通过切面配合注解的方式使用。

注意:切面不能应用于静态方法,私有方法,注解要被代理对象调用。

1.注解

@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface RedisLock {

    String name() default "";

    String key() default "";

    int waitTime() default 5;

    int expireTime() default -1;

    TimeUnit timeUnit() default TimeUnit.SECONDS;

    String notes() default "";

    String[] tags() default {""};
}

 2.切面

@Aspect
@Component
public class RedisLockAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(RedisLockAspect.class);

    private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";

    @Lazy
    @Resource
    private RedissonClient redissonClient;

    /**
     * 定义切点
     */
    @Pointcut("@annotation(mairuirobot.iwarehousecontrol.framework.functions.iwc.redis.annotation.RedisLock)")
    public void redisLockPointcut() {
    }

    /**
     * 环绕通知
     */
    @Around("redisLockPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        String comment;
        // 获取方法上的注解 RedisLock
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        RedisLock redisLock = method.getAnnotation(RedisLock.class);
        String name = redisLock.name();
        String spel = redisLock.key();
        String key = getRedisKey(joinPoint, name, spel);
        RLock rLock = redissonClient.getLock(key);

        boolean lock = false;
        Object result = null;
        try {
            // long waitTime-获取锁的等待时长;long leaseTime-持有锁的时间,-1代表默认启动看门狗机制;TimeUnit unit-时间单位
            lock = rLock.tryLock(redisLock.waitTime(), redisLock.expireTime(), redisLock.timeUnit());
            if (!lock) {
                comment = String.format("Redis key[%s] lock failed, it's a repeated message", key);
                LOGGER.error(comment);
                Class<?> clazz = ((MethodSignature) joinPoint.getSignature()).getReturnType();
                if (GeneralResponse.class == clazz) {
                    return GeneralResponse.failure();
                }
                if (boolean.class == clazz || Boolean.class == clazz) {
                    return false;
                }
                return GeneralResponse.failure();
            }
            result = joinPoint.proceed();
        } finally {
            if (lock) {
                try {
                    rLock.unlock();
                } catch (IllegalMonitorStateException e) {
                    comment = String.format("Redis key[%s] unlock failed: errMsg = ", key);
                    LOGGER.error(comment, e);
                }
            } else {
                comment = String.format("Current thread did not acquire the redis key[%s] lock, skipping unlock", key);
                LOGGER.error(comment);
            }
        }
        return result;
    }

    private String getRedisKey(ProceedingJoinPoint joinPoint, String lockName, String spel) {
        Object[] arguments = joinPoint.getArgs();
        String key = REDISSON_LOCK_PREFIX + lockName + ":" + SpelUtil.parse(spel, arguments);
        return key;
    }
}

3.解析方法(需要根据你实际情况进行修改)

public class SpelUtil {

    public static String parse(String spel, Object[] args) {
        if (spel == null || spel.isEmpty()) return "";
        Map<Object, Object> resMap = new HashMap<>();
        String[] split = spel.split("\\.");
        Arrays.stream(args).forEach(arg -> {
            JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(arg));
            jsonObject.forEach((key, value) -> {
                if (value instanceof JSONObject) {
                    ((JSONObject) value).forEach((k, v) -> {
                        resMap.put(k, v);
                    });
                } else {
                    resMap.put(key, value);
                }
            });

        });
        try {
            String key = split[split.length - 1];
            Object value = resMap.get(key);
            return (value != null) ? value.toString() : "";
        } catch (Exception e) {
            throw new RuntimeException("redisson参数解析失败: " + spel, e);
        }
    }
}

4.注册bean 

@Configuration
public class MyRedisRegistration {

    @Value("${redisson.address:}")
    private String redissonAddress;

    @Value("${redisson.password:}")
    private String redissonPassword;

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress(redissonAddress).setPassword(redissonPassword);
        return Redisson.create(config);
    }
}

 场景:申请电梯资源的时候,会有很多请求进来,导致电梯资源被争夺,这时就需要锁定电梯资源,防止同一个设备被抢占。


网站公告

今日签到

点亮在社区的每一天
去签到