【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件(二)

简介: 【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件

【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件(一)https://developer.aliyun.com/article/1471009


定义我们分布式锁的基础抽象类

接下来我们就定一下我们分布式锁的一个基础抽象类:AbstractDistributeLockSupport。这个类主要实现了我们之前的那个接口DistributeLockSupport。

java

复制代码

public abstract class AbstractDistributeLockSupport<T> implements DistributeLockSupport<T> {
    /**
     * 检验参数
     * @param distributeLockParam
     * @return
     */
    protected DistributeLockParam fullDistributeDefaultValue(DistributeLockParam distributeLockParam){
        Preconditions.checkNotNull(distributeLockParam,"检测到了参数不允许为空!");
        DistributeLockType distributeLockType = distributeLockParam.getLockType();
        distributeLockParam.setLockType(Optional.ofNullable(distributeLockType).orElse(DistributeLockType.FAIR_LOCK));
        distributeLockParam.setExpireTime(Optional.ofNullable(distributeLockParam.getExpireTime()).orElse(DEFAULT_EXPIRE_TIME));
        distributeLockParam.setWaitTime(Optional.ofNullable(distributeLockParam.getExpireTime()).orElse(DEFAULT_WAIT_TIME));
        distributeLockParam.setTimeUnit(Optional.ofNullable(distributeLockParam.getTimeUnit()).orElse(TimeUnit.SECONDS));
        return distributeLockParam;
    }
    /**
     * 构建相关的锁key值
     * @param distributeLockParam
     * @return
     */
    protected String buildLockKey(DistributeLockParam distributeLockParam){
        String lockId = StringUtils.defaultIfEmpty(distributeLockParam.getLockUUid(),
                        UUID.fastUUID().toString());
        distributeLockParam.setLockUUid(lockId);
        String delmiter = StringUtils.defaultIfEmpty(distributeLockParam.getDelimiter(),
                            DEFAULT_DELIMTER);
        distributeLockParam.setDelimiter(delmiter);
        String prefix = StringUtils.defaultIfEmpty(distributeLockParam
                .getLockNamePrefix(),DEFAULT_KEY_PREFIX);
        distributeLockParam.setLockNamePrefix(prefix);
        String lockFullName = "";
        if(!delmiter.equals(DEFAULT_DELIMTER)){
            //todo 待优化
            Joiner joiner = Joiner.on(delmiter).skipNulls();
            lockFullName = joiner.join(prefix,lockId);
        }else{
            lockFullName = DEFAULT_JOINER.join(prefix,lockId);
        }
        return lockFullName;
    }

该类主要包含两个方法。分别是fullDistributeDefaultValue和buildLockKey。

fullDistributeDefaultValue方法

这个方法主要的目的是为了校验以及填充一些我们没有写的参数的默认值。

java

复制代码

protected DistributeLockParam fullDistributeDefaultValue(DistributeLockParam distributeLockParam){
        Preconditions.checkNotNull(distributeLockParam,"检测到了参数不允许为空!");
        DistributeLockType distributeLockType = distributeLockParam.getLockType();
        distributeLockParam.setLockType(Optional.ofNullable(distributeLockType).orElse(DistributeLockType.FAIR_LOCK));
        distributeLockParam.setExpireTime(Optional.ofNullable(distributeLockParam.getExpireTime()).orElse(DEFAULT_EXPIRE_TIME));
        distributeLockParam.setWaitTime(Optional.ofNullable(distributeLockParam.getExpireTime()).orElse(DEFAULT_WAIT_TIME));
        distributeLockParam.setTimeUnit(Optional.ofNullable(distributeLockParam.getTimeUnit()).orElse(TimeUnit.SECONDS));
        return distributeLockParam;
}

buildLockKey方法

该类主要负责的是构建我们的分布式锁的key

java

复制代码

protected String buildLockKey(DistributeLockParam distributeLockParam){
        String lockId = StringUtils.defaultIfEmpty(distributeLockParam.getLockUUid(),
                        UUID.fastUUID().toString());
        distributeLockParam.setLockUUid(lockId);
        String delmiter = StringUtils.defaultIfEmpty(distributeLockParam.getDelimiter(),
                            DEFAULT_DELIMTER);
        distributeLockParam.setDelimiter(delmiter);
        String prefix = StringUtils.defaultIfEmpty(distributeLockParam
                .getLockNamePrefix(),DEFAULT_KEY_PREFIX);
        distributeLockParam.setLockNamePrefix(prefix);
        String lockFullName = "";
        if(!delmiter.equals(DEFAULT_DELIMTER)){
            //todo 待优化
            Joiner joiner = Joiner.on(delmiter).skipNulls();
            lockFullName = joiner.join(prefix,lockId);
        }else{
            lockFullName = DEFAULT_JOINER.join(prefix,lockId);
        }
        return lockFullName;
}

从在马上可以看出来,他主要就是将我们之前的那些所有的属性进行连接拼接到一起。

至此,我们的基础组建部分的抽象部分就已经完成了。那么接下来呢我们需要进行一个实现Redis模式下的分布式锁。


定义Redis分布式锁的注解

主要用于AOP的一个拦截以及获取一些特定化的参数。

RedisDistributedLock注解

java

复制代码

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface RedisDistributedLock {
    String prefix() default "";
    /**
     * 锁过期时间
     */
    int expireTime() default 30;
    /**
     * 获取锁等待时间
     */
    int waitTime() default 10;
    TimeUnit timeUnit() default TimeUnit.SECONDS;
    String delimiter() default ":";
    LockCategory category() default LockCategory.COMMON;
}

RedisDistributedLockParam注解

主要用于参数方法上的修饰,获取参数相关的一些主要用于参数方法上的修饰,获取参数相关的一些参数值作为我们的分布式主键的key。

java

复制代码

@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface RedisDistributedLockParam {
    String name() default "";
}

实现分布式锁的唯一键的生成器

我们定义分布式锁组件抽象接口的redis版本为RedisDistributedLockKeyGenerator。

java

复制代码

public class RedisDistributedLockKeyGenerator  implements LockKeyGenerator {
    @Override
    public String getLockKey(ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        RedisDistributedLock lockAnnotation = method.getAnnotation(RedisDistributedLock.class);
        final Object[] args = pjp.getArgs();
        final Parameter[] parameters = method.getParameters();
        StringBuilder builder = new StringBuilder();
        // 默认解析方法里面带 CacheParam 注解的属性,如果没有尝试着解析实体对象中的
        for (int i = 0; i < parameters.length; i++) {
            final RedisDistributedLockParam annotation = parameters[i].getAnnotation(RedisDistributedLockParam.class);
            if (annotation == null) {
                continue;
            }
            builder.append(lockAnnotation.delimiter()).append(args[i]);
        }
        if (StringUtils.isEmpty(builder.toString())) {
            final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            for (int i = 0; i < parameterAnnotations.length; i++) {
                final Object object = args[i];
                final Field[] fields = object.getClass().getDeclaredFields();
                for (Field field : fields) {
                    final RedisDistributedLockParam annotation = field.getAnnotation(RedisDistributedLockParam.class);
                    if (annotation == null) {
                        continue;
                    }
                    field.setAccessible(true);
                    builder.append(lockAnnotation.delimiter()).append(ReflectionUtils.getField(field, object));
                }
            }
        }
        return lockAnnotation.prefix() + builder.toString();
    }
}

上面的码主要是用鱼上面的代码主要是用鱼去提取注解上的参数以及一些呃参数的key的一个基本信息。

实现分布式锁实现类RedisDistributeLockSupport

RedisDistributeLockSupport主要实现了我们的抽象分布式锁的核心业务接口。

其中使用了Redisson的RedissonClient客户端服务,从而进行选择类型,进行选择分布式锁的方式。

java

复制代码

@Slf4j
@Component
public class RedisDistributeLockSupport extends AbstractDistributeLockSupport<RLock> {
    @Autowired
    RedissonClient redissonClient;
    /**
     * 非阻塞方式锁
     * @param distributeLockParam
     * @return
     */
    @Override
    public RLock lock(DistributeLockParam distributeLockParam) {
        distributeLockParam = fullDistributeDefaultValue(distributeLockParam);
        String lockKey = buildLockKey(distributeLockParam);
        RLock rLock = null;
        try {
            switch (distributeLockParam.getLockType()) {
                // 可重入锁
                case REENTRANT_LOCK: {
                    rLock = redissonClient.getLock(lockKey);
                    break;
                }
                // 非公平锁
                case FAIR_LOCK: {
                    rLock = redissonClient.getFairLock(lockKey);
                    break;
                }
                default: {
                    throw new UnsupportedOperationException("暂时不支持此种方式的锁!");
                }
            }
            Boolean result = rLock.tryLock(distributeLockParam.getWaitTime(), distributeLockParam.getExpireTime(), distributeLockParam.getTimeUnit());
            return rLock;
        } catch (InterruptedException e) {
            log.error("加锁为阻塞模式下的锁进行失败!", e);
            return rLock;
        }
    }
    @Override
    public void unlock(RLock param, DistributeLockParam distributeLockParam) {
        try {
            param.unlock();
        } catch (Exception e) {
            log.error("解我操!啊?锁为阻塞模式下的锁进行失败!", e);
        }
    }
}

可以根据我们所的类型选择。公平锁或者是和重入锁。

实现分布式锁实现类RedisDistributedLockAspect切面类

java

复制代码

@Aspect
@Order(4)
@Slf4j
public class RedisDistributedLockAspect {
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RedisDistributedLockKeyGenerator redisDistributedLockKeyGenerator;
    @Around("execution(public * *(..)) && @annotation(com.hyts.assemble.distributeLock.redis.RedisDistributedLock)")
    public Object interceptor(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        RedisDistributedLock redisDistributedLock = method.getAnnotation(RedisDistributedLock.class);
        if (StringUtils.isEmpty(redisDistributedLock.prefix())) {
            throw new RuntimeException("lock key can't be null...");
        }
        final String lockKey = redisDistributedLockKeyGenerator.getLockKey(pjp);
        RLock lock = chooseLock(redisDistributedLock,lockKey);
        //key不存在才能设置成功
        Boolean success = null;
        Object proceed = null;
        try {
            success = lock.tryLock(redisDistributedLock.waitTime(), redisDistributedLock.expireTime(), redisDistributedLock.timeUnit());
            if (success) {
                log.debug("tryLock success key [{}]", lockKey);
                proceed = pjp.proceed();
            } else {
                log.error("key is : {" + lockKey + "} tryLock fail ");
                throw new RedisDistributedLockException(lockKey);
            }
        } catch (InterruptedException e) {
            log.error("key is : {" + lockKey + "} tryLock error ", e);
            throw new RedisDistributedLockException(lockKey, e.getMessage());
        } finally {
            if (success) {
                log.debug("unlock [{}]", "key:" + lockKey);
                lock.unlock();
            }
        }
        return proceed;
    }
    private RLock chooseLock(RedisDistributedLock redisDistributedLock, String lockName) {
        LockCategory category = redisDistributedLock.category();
        switch (category) {
            case FAIR:
                return redissonClient.getFairLock(lockName);
        }
        return redissonClient.getLock(lockName);
    }
}



相关文章
|
8月前
|
负载均衡 测试技术 调度
大模型分布式推理:张量并行与流水线并行技术
本文深入探讨大语言模型分布式推理的核心技术——张量并行与流水线并行。通过分析单GPU内存限制下的模型部署挑战,详细解析张量并行的矩阵分片策略、流水线并行的阶段划分机制,以及二者的混合并行架构。文章包含完整的分布式推理框架实现、通信优化策略和性能调优指南,为千亿参数大模型的分布式部署提供全面解决方案。
2502 4
|
8月前
|
存储 缓存 安全
某鱼电商接口架构深度剖析:从稳定性到高性能的技术密码
某鱼电商接口架构揭秘:分层解耦、安全加固、性能优化三维设计,实现200ms内响应、故障率低于0.1%。详解三层架构、多引擎存储、异步发布、WebSocket通信与全链路防护,助力开发者突破电商接口“三难”困境。
|
8月前
|
人工智能 自然语言处理 安全
AI助教系统:基于大模型与智能体架构的新一代教育技术引擎
AI助教系统融合大语言模型、教育知识图谱、多模态交互与智能体架构,实现精准学情诊断、个性化辅导与主动教学。支持图文语音输入,本地化部署保障隐私,重构“教、学、评、辅”全链路,推动因材施教落地,助力教育数字化转型。(238字)
1550 23
|
8月前
|
Java Linux 虚拟化
【Docker】(1)Docker的概述与架构,手把手带你安装Docker,云原生路上不可缺少的一门技术!
1. Docker简介 1.1 Docker是什么 为什么docker会出现? 假定您在开发一款平台项目,您的开发环境具有特定的配置。其他开发人员身处的环境配置也各有不同。 您正在开发的应用依赖于您当前的配置且还要依赖于某些配置文件。 您的企业还拥有标准化的测试和生产环境,且具有自身的配置和一系列支持文件。 **要求:**希望尽可能多在本地模拟这些环境而不产生重新创建服务器环境的开销 问题: 要如何确保应用能够在这些环境中运行和通过质量检测? 在部署过程中不出现令人头疼的版本、配置问题 无需重新编写代码和进行故障修复
720 2
|
8月前
|
存储 人工智能 搜索推荐
拔俗AI助教系统:基于大模型与智能体架构的新一代教育技术引擎
AI助教融合大语言模型、教育知识图谱、多模态感知与智能体技术,重构“教、学、评、辅”全链路。通过微调LLM、精准诊断错因、多模态交互与自主任务规划,实现个性化教学。轻量化部署与隐私保护设计保障落地安全,未来将向情感感知与教育深度协同演进。(238字)
1114 0
|
10月前
|
存储 负载均衡 NoSQL
【赵渝强老师】Redis Cluster分布式集群
Redis Cluster是Redis的分布式存储解决方案,通过哈希槽(slot)实现数据分片,支持水平扩展,具备高可用性和负载均衡能力,适用于大规模数据场景。
732 2
|
10月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
799 6
|
11月前
|
存储 缓存 NoSQL
Redis核心数据结构与分布式锁实现详解
Redis 是高性能键值数据库,支持多种数据结构,如字符串、列表、集合、哈希、有序集合等,广泛用于缓存、消息队列和实时数据处理。本文详解其核心数据结构及分布式锁实现,帮助开发者提升系统性能与并发控制能力。
|
数据采集 存储 数据可视化
分布式爬虫框架Scrapy-Redis实战指南
本文介绍如何使用Scrapy-Redis构建分布式爬虫系统,采集携程平台上热门城市的酒店价格与评价信息。通过代理IP、Cookie和User-Agent设置规避反爬策略,实现高效数据抓取。结合价格动态趋势分析,助力酒店业优化市场策略、提升服务质量。技术架构涵盖Scrapy-Redis核心调度、代理中间件及数据解析存储,提供完整的技术路线图与代码示例。
1878 0
分布式爬虫框架Scrapy-Redis实战指南

热门文章

最新文章