Redis+AOP实现一个可通用的分布式锁——改进

news2025/7/5 18:42:08

目录

    • 前言
    • 方案改进
    • 思考与总结

前言

上一次利用Redis分布式锁解决了一个并发问题:
上篇:利用Redis分布式锁解决集群服务器定时任务重复执行问题
代码可以直接从上篇文章中拿到,本篇文章仅对上次文章内容做进一步改进

主要思想是:利用AOP面向切面的编程思想,将加锁部分抽象成一个切面,并利用自定义注解。

但是有不足的地方:

  1. 如下是上篇文章中提到的CacheLock注解的参数,一般情况下,锁都会有等待时间waitTime默认为0不太合适,且默认都需要异常抛出会更好。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheLock {
    String lockedKey() default "";   //redis锁key的前缀
    long expireTime() default 10;    //key在redis里存在的时间 单位:秒
    boolean release() default true; //释放在方法执行完成之后释放锁
    long waitTime() default 0; //获取锁的最大等待时间,单位:秒,默认不等待,0即为快速失败
    boolean throwException() default false;//是否抛出异常 默认不抛出
}
  1. 其次,默认的redis锁的前缀,是固定的字符串,不具备方法可以根据入参信息,来指定key。
    如下代码是注解的具体使用,如果需要按照入参name来作为key锁定,则按照之前的实现是不支持的。
//测试服务接口
public interface TestService {
    void testAspect(String name);
}

//测试服务类
@Slf4j
@Service
public class TestServiceImpl implements TestService {
	
    @Override
    @CacheLock(lockedKey = "CacheLockAspectTest", expireTime = 10)
    public void testAspect(String name) {
        log.info("任务:"+ name +"方法获取到锁了!时间:"+ new Date());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("任务:"+ name +"方法执行完成了!"+"时间:"+ new Date());
    }
}

那么现在就是主要对实现根据指定的方法入参作为锁的key,进一步实现分布式锁。
同样我希望它具备一些灵活性,那么也需要借助注解,只有方法入参前有该注解,那么就会把这个入参作为key值。

方案改进

我希望我的注解在使用的时候更加灵活和简单,让多的情况是这样(伪代码):
我的redis分布式锁的key为:
key=前缀+方法名称+入参

@Service
public class TestServiceImpl implements TestService {
	
    @Override
    @CacheLock
    public void testAspect(@CacheLockKey String name) {
        log.info("任务:"+ name +"方法获取到锁了!时间:"+ new Date());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("任务:"+ name +"方法执行完成了!"+"时间:"+ new Date());
    }
}

具体内容:

(1)首先就是需要实现CacheLockKey 注解:

/**
 * 分布式锁key 作用在方法入参上,则会拼接为key值
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheLockKey {

}

(2)在切面方法中,获取全部入参信息,并找到带有该注解的参数,将其拼接为key值

改的点:
在这里插入图片描述
代码:

//获取指定的lockedKey参数,如果没有,则直接取方法名称作为key值的前缀
StringBuilder lockKey = new StringBuilder(cacheMethod.getAnnotation(CacheLock.class).lockedKey());
        if(StringUtils.isBlank(lockKey.toString())){
            lockKey.append(cacheMethod.getName()).append("-");
        }

        //参数注解,1维是参数,2维是注解
        Object[] params = pjp.getArgs();
        Annotation[][] annotations = cacheMethod.getParameterAnnotations();
        for (int i = 0; i < annotations.length; i++) {
            Object param = params[i];
            Annotation[] paramAnn = annotations[i];
            //参数为空,直接下一个参数
            if(param == null || paramAnn.length == 0){
                continue;
            }
            for (Annotation annotation : paramAnn) {
                //这里判断当前注解是否为CacheLockKey.class
                if(annotation.annotationType().equals(CacheLockKey.class)){
                    lockKey.append(param).append("-");
                    break;
                }
            }
        }

        log.info("lockKey:{}", lockKey.toString());

(3)稍微改进一下CacheLock注解的默认参数

/**
 * 分布式锁注解信息
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheLock {
    String lockedKey() default "";   //redis锁key的前缀
    long expireTime() default 10;    //key在redis里存在的时间 单位:秒
    boolean release() default true; //释放在方法执行完成之后释放锁
    long waitTime() default 10; //获取锁的最大等待时间,单位:秒,默认为10s,如果为0则未获取到锁直接失败
    boolean throwException() default true;//是否抛出异常 默认抛出
}

思考与总结

实际上,以上内容还有可以改进的点:
1.仅把方法名称和入参信息作为key值,会不会存在重复?
2.入参作为key但是入参为空,怎么处理?
3.如果key的锁定设定的时长失效了,方法还未执行完成,怎么办?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/7142.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一篇读懂|Linux系统平均负载

我们经常会使用 top 命令来查看系统的性能情况&#xff0c;在 top 命令的第一行可以看到 load average 这个数据&#xff0c;如下图所示&#xff1a; load average 包含 3 列&#xff0c;分别表示 1 分钟、5 分钟和 15 分钟的 系统平均负载。 对于系统平均负载这个数值&#x…

红杉官网已删长文:伴随SBF一路走来的救世主情结(上)

每个创业公司都有一个创业故事。苹果是洛斯阿尔托斯车库里的两个黑客。谷歌是斯坦福大学宿舍里的两个研究生。而Alameda Research是伯克利公寓里做着加密货币交易的一个人。这个人叫山姆班克曼弗里德&#xff0c;朋友们都叫他SBF。然而&#xff0c;他所做的交易——最终催生了加…

ERP系统如何改善企业的业务?

ERP代表 "企业资源计划"&#xff0c;指的是企业用来计划和管理日常活动的一种软件或系统&#xff0c;如供应链、制造、服务、财务和其他流程。ERP系统可用于自动化和简化整个企业或组织的个别活动&#xff0c;如会计和采购、项目管理、客户关系管理、风险管理、合规和…

springboot常用组件的集成

目录 springboot常用组件的集成 1.创建项目 2. web服务器配置 3. 配置数据库 4. 配置mybatis 5. 开启事务 6.aop配置 7. pagehelper分页 3. druid数据库连接池 4. 集成redis 编写一个controller用于测试 2.手动装配redis 1.创建项目 1.idea创建项目 创建步骤 &am…

PDF文档编辑Acrobat Pro DC

acrobat dc2022不仅可以轻松的帮助用户打开任意的PDF格式文件&#xff0c;还能随意的对其进行编辑、压缩、合并、剪裁、旋转。删除、分割、重新排序页面等操作。全新的统一分享体验使您能够跨桌面&#xff0c;移动和Web进行文档协作。共享PDF链接以查看或评论。在任何设备上的任…

初识jQuery

jQuery简介 What is jQuery? jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitud…

【附源码】计算机毕业设计JAVA宠物医院管理

【附源码】计算机毕业设计JAVA宠物医院管理 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA mybati…

经典动画库 animate.css 的应用

一、animate.css animate.css&#xff1a;&#xff1a;Animate.css 就像嗑水那么简单的CSS动画。 官网&#xff1a;Redirecting to Animate.css Animate.css是一个纯CSS动画库&#xff0c;其核心技术使用了 CSS3 里的 keyframes 和 animation。 不兼容IE10以下的 IE 浏览器。…

SpringMVC基于注解使用:异常处理

SpringMVC基于注解使用&#xff1a;异常处理 1、内置异常处理解析器 2、统一异常处理 ControllerAdvice 是Spring3.2提供的新注解,它是对Controller的增强,可对 controller中被 RequestMapping注解的方法加一些逻辑处理: 全局异常处理&#xff08;较为常用)全局数据绑定全局…

基于PSO的UAV三维路径规划(Matlab代码实现)

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

ArcGIS计算地形湿度指数

TWI是区域地形对径流流向和蓄积影响的物理指标&#xff0c;有助于识别降雨径流模式、潜在土壤含水量增加区域和积水区域。 计算方法&#xff1a;TWI是通过细尺度地形与上梯度对地表面积的贡献相互作用&#xff0c;根据以下关系得到的(Beven et al.,1979) [1] : TWI ln [CA/…

行深智能亮相乌镇互联网大会,荣获直通乌镇全球互联网大赛一等奖

11月9-11日&#xff0c;2022年世界互联网大会在浙江乌镇举行&#xff0c;本届大会以“共建网络世界、共创数字未来——携手构建网络空间命运共同体”为主题&#xff0c;吸引了来自世界各地的政府、国际组织、企业参加。 行深智能携系列无人车及解决方案在乌镇运河智能汽车文化…

react-hooks的节流与闭包,以及useCallback的用处

目录 useThrottle: 封装了一个节流的hook useCallback的作用&#xff08;性能优化&#xff09; 不用Hook封装节流方法的情况&#xff0c;看是怎么形成闭包的&#xff1a; useThrottle: 封装了一个节流的hook import { useEffect, useCallback, useRef } from react;function…

2023年软件测试的发展如何?

近些年&#xff0c;自动化测试在很多软件公司已经成为一种必备的测试方式。即使那些还没运用自动化测试手段的公司&#xff0c;也正开始着手筹划了。每年&#xff0c;我们从举办的各种测试论坛和峰会上可以发现&#xff0c;自动化测试和敏捷测试必定是会议的主角。再看看最具有…

IPV6地址详解

♥️作者&#xff1a;小刘在C站 ♥️每天分享课堂笔记&#xff0c;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的&#xff0c;绽放。 目录 一.为什么要使用IPv6 二. ipv4 三. ipv6 地址&#xff0c; 四 ipv6与 ipv4 地址相比 1.v4…

MySQL数据库 -- 表的增删查改

今天来讲MySQL数据库的表增删查改操作。今天主要是通过栗子来演示语法使用的&#xff0c;话不多说&#xff0c;直奔主题~ 表的增删查改&#xff1a; CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; 目录 Cre…

你适合做自动化测试吗?

上一篇对于自动化测试有了基础了解&#xff0c;这一篇我们来看看你适合做自动化测试吗&#xff1f; 你适合走自动化测试这条路吗&#xff1f; 不管是UI自动化还是接口自动化&#xff0c;肯定的一点是&#xff0c;必须有代码基础&#xff0c;不管是java还是python。所以如果你…

Docker 安装Oracle 11g免费版—无坑小白白版(值得拥有)

​ Docker 安装Oracle 11g免费版—无坑小白白版&#xff08;值得拥有&#xff09; 第一步&#xff1a;登录自己的服务器&#xff08;root用户/或授权用户&#xff09; 第二步&#xff1a;下载 1、下载镜像 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_…

基于概率距离削减法、蒙特卡洛削减法的风光场景不确定性削减附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

MySQL数据库期末考试试题及参考答案(01)

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 一、 填空题 ___在20世纪80年代被美国国家标准学会和国际标准化组织定义为关系型数据库语言的标准。数据模型所描述的内容包括3个部分&#xff0c;分别是数据结构、数据操作…