自定义注解 + AOP + Redisson:优雅实现分布式锁(增强版)

文章目录

在分布式系统中,保证数据一致性和避免并发冲突是一个常见的挑战。分布式锁是解决这一问题的有效手段。本文将介绍如何通过自定义注解AOP(面向切面编程)Redisson ,优雅地实现分布式锁,并支持注解中的SpEL表达式 ,动态生成锁的Key。同时,我们将通过PlantUML描述请求的执行流程,帮助你更好地理解整个机制。


什么是分布式锁?

分布式锁是一种在分布式系统中用于控制多个进程或线程对共享资源访问的机制。它的核心目标是:

  • 互斥性:同一时刻只有一个客户端可以持有锁。
  • 可重入性:同一个客户端可以多次获取同一把锁。
  • 高可用性:锁服务需要具备高可用性,避免单点故障。
  • 自动释放:锁需要支持超时自动释放,避免死锁。

为什么选择Redisson?

Redisson是一个基于Redis的Java客户端,提供了丰富的分布式对象和服务,包括分布式锁。它的优势在于:

  1. 简单易用:提供了简洁的API,易于集成。
  2. 高性能:基于Redis的高性能特性,支持高并发场景。
  3. 功能丰富:支持可重入锁、公平锁、读写锁等多种锁类型。
  4. 自动续期:支持锁的自动续期,避免锁过期问题。

实现思路

我们将通过以下步骤实现分布式锁:

  1. 自定义注解 :定义一个注解@DistributedLock,支持SpEL表达式动态生成锁的Key。
  2. AOP切面 :通过AOP拦截被@DistributedLock注解标记的方法,在方法执行前后加锁和释放锁。
  3. Redisson配置:集成Redisson客户端,提供分布式锁的实现。
  4. 请求执行流程:通过PlantUML描述请求的执行流程,帮助理解整个机制。

代码实现

1. 自定义注解

定义一个注解@DistributedLock,支持SpEL表达式动态生成锁的Key:

java 复制代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributedLock {
    String key(); // 锁的key,支持SpEL表达式
    long waitTime() default 30; // 获取锁的最大等待时间(秒)
    long leaseTime() default 10; // 锁的持有时间(秒)
}

2. AOP切面

通过AOP拦截被@DistributedLock注解标记的方法,在方法执行前后加锁和释放锁。使用SpEL表达式解析动态Key:

java 复制代码
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class DistributedLockAspect {

    @Autowired
    private RedissonClient redissonClient;

    @Around("@annotation(distributedLock)")
    public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
        // 解析SpEL表达式,生成锁的Key
        String lockKey = parseSpEL(joinPoint, distributedLock.key());

        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试获取锁
            boolean isLocked = lock.tryLock(distributedLock.waitTime(), distributedLock.leaseTime(), java.util.concurrent.TimeUnit.SECONDS);
            if (!isLocked) {
                throw new RuntimeException("获取分布式锁失败");
            }

            // 执行目标方法
            return joinPoint.proceed();
        } catch (Exception e) {
            // 处理异常
            throw e;
        } finally {
            // 释放锁
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 解析SpEL表达式,生成锁的Key
     */
    private String parseSpEL(ProceedingJoinPoint joinPoint, String spEL) {
        // 获取方法参数名和值
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String[] parameterNames = signature.getParameterNames();
        Object[] args = joinPoint.getArgs();

        // 创建SpEL上下文
        StandardEvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i], args[i]);
        }

        // 解析SpEL表达式
        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(spEL);
        return expression.getValue(context, String.class);
    }
}

3. Redisson配置

配置Redisson客户端,连接到Redis服务器:

java 复制代码
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedissonConfig {

    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer()
              .setAddress("redis://127.0.0.1:6379")
              .setPassword("your_password") // 如果有密码
              .setDatabase(0);
        return Redisson.create(config);
    }
}

4. 使用示例

在业务代码中使用@DistributedLock注解,标记需要加锁的方法。通过SpEL表达式动态生成锁的Key:

java 复制代码
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @DistributedLock(key = "'order_lock_' + #orderId", waitTime = 10, leaseTime = 5)
    public void createOrder(String orderId) {
        // 业务逻辑
        System.out.println("创建订单:" + orderId);
    }
}

请求执行流程

以下是请求的执行流程


总结

通过自定义注解、AOP和Redisson,我们可以优雅地实现分布式锁,并支持SpEL表达式动态生成锁的Key。本文详细介绍了实现思路和代码示例,并通过PlantUML描述了请求的执行流程,帮助你更好地理解整个机制。

如果你在开发中遇到类似问题,不妨尝试本文提供的解决方案,提升系统的并发处理能力!


关于作者

我是Java开发领域的专家,专注于高质量代码的设计与实现。如果你对Java技术感兴趣,欢迎关注我的博客,我们一起学习进步!

相关推荐
珠海西格18 小时前
“主动预防” vs “事后补救”:分布式光伏防逆流技术的代际革命,西格电力给出标准答案
大数据·运维·服务器·分布式·云计算·能源
小邓吖21 小时前
自己做了一个工具网站
前端·分布式·后端·中间件·架构·golang
曹天骄1 天前
基于 Cloudflare Worker 构建分布式测速调度系统:KV 与 D1 数据层设计实战教程
分布式·缓存
Prince-Peng1 天前
技术架构系列 - 详解Redis
数据结构·数据库·redis·分布式·缓存·中间件·架构
曹天骄1 天前
基于 Cloudflare Worker + KV 构建高性能分布式测速调度系统(工程实战)
分布式
奋进的芋圆1 天前
Spring Boot 3 高并发事务与分布式事务企业级完整解决方案
spring boot·分布式
淡泊if1 天前
Kafka部署模式详解:从单机到分布式集群的核心选择
分布式·kafka
鱼跃鹰飞1 天前
面试题:什么是时钟回拨问题?怎么解决
分布式·系统架构
无心水1 天前
分布式环境下定时任务与SELECT FOR UPDATE的陷阱与解决方案
分布式·后端·wpf·xxl-job·quartz·定时任务·selectforupdate
缘友一世1 天前
大模型分布式推理:Ray 与 vLLM/Transformers 的协同架构深度解析
分布式·架构·transformer·ray·vllm