一个注解完美实现分布式锁(AOP)

前言

        学习过Spring的小伙伴都知道AOP的强大,本文将通过Redisson结合AOP,仅需一个注解就能实现分布式锁。 🍭 


不会使用aop和redisson的小伙伴可以参考:

【学习总结】使Aop实现自定义日志注解-CSDN博客

【学习总结】使用分布式锁和乐观锁解决“超卖”问题-CSDN博客

前提

有小伙伴可能会看不懂下面对key的一些操作,当key为null时,使用StringBuilder手动拼接key,不为null时,主要使用到了SpEl表达式。

  • 使用Spring Expression Language (SpEL)来支持在`@DLock`注解的`value`属性中定义动态key。 
  • 使用`StandardEvaluationContext`和`DefaultParameterNameDiscoverer`来解析方法参数名,并将它们作为变量存储在SpEL的上下文中。
  • 使用`SpelExpressionParser`来解析key字符串中的SpEL表达式,并获取最终的key值。

代码

自定义注解:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DLock {//分布式锁的keyString value() default "";
}

  value属性定义了分布式锁的key,默认为空,如果为空会根据当前注解的类及方法参数等生成key。

切面定义:

@Component
@Aspect
public class DistributedLockAspect {private final RedissonClient redisson;public DistributedLockAspect(RedissonClient redissonClient){this.redisson = redissonClient;;}//定义切面@Pointcut("@annotation(lock)")private void lockPointcut(DLock lock){}@Around("lockPointcut(lock)")public Object lockAround(ProceedingJoinPoint point,DLock lock) throws Throwable{//从ProceedingJoinPoint对象中获取目标方法的签名,并将其强制转换为MethodSignature类型MethodSignature signature = (MethodSignature)point.getSignature();//获取目标对象的方法Method method = signature.getMethod();//获取目标方法的参数数组Object[] args = point.getArgs();//定义分布式锁keyString key = lock.value();if ("".equals(key)){//根据当前的类名+方法参数信息生成keykey = configKey(signature.getDeclaringType(), method).replaceAll("[^a-zA-Z0-9]", "") ;System.out.println(key);}else {//支持SpEL表达式StandardEvaluationContext context = new StandardEvaluationContext();//将当前方法参数信息都存入到SpEl执行的上下文中DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();String[] parameterNames = discoverer.getParameterNames(method);for (int i = 0,len = parameterNames.length; i < len; i++){context.setVariable(parameterNames[i],args[i]);}ExpressionParser parser = new SpelExpressionParser();Expression expression = parser.parseExpression(key);key = expression.getValue(context,String.class);}//加锁RLock rLock = redisson.getLock(key);rLock.lock();try {//执行业务代码Object o = point.proceed();return o;}finally {rLock.unlock();}}private String configKey(Class<?> targetType, Method method) {StringBuilder builder = new StringBuilder();builder.append(targetType.getSimpleName());builder.append('#').append(method.getName()).append('(');for (Class<?> param : method.getParameterTypes()){builder.append(param.getSimpleName()).append(',');}if (method.getParameterTypes().length > 0){builder.deleteCharAt(builder.length() - 1);}return builder.append(')').toString();}
}

以上是基于注解实现分布式锁的核心类都定义完成了,接下来进行测试。

@GetMapping("/stock")@DLock("'user:' + #userId + ':' + #productId")@Transactionalpublic String decStocks(@RequestParam Long userId, @RequestParam Integer productId){//查询商品信息Products product = productsService.getById(productId);//获取商品库存Integer stockQuantity = product.getStockQuantity();if (stockQuantity > 0){UpdateWrapper<Products> updateWrapper = new UpdateWrapper<>();updateWrapper.eq("id",productId).setSql("stock_quantity = stock_quantity - 1");boolean result = productsService.update(updateWrapper);if (result){return "商品库存呢扣减成功";}}return "商品卖完了!";}

我就以一个简单的商品超卖的例子进行测试

假设库存为10

使用JMeter进行测试

测试结果

没有出现库存为负数的情况,非常成功,说明我们的锁注解起作用了。


总结

有兴趣的小伙伴可以试一试。

参考文章:

https://mp.weixin.qq.com/s/Bkhg74dE9HilE7PFtqj-5wicon-default.png?t=N7T8https://mp.weixin.qq.com/s/Bkhg74dE9HilE7PFtqj-5w

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

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

相关文章

CSS 鼠标经过放大元素 不影响其他元素

效果 .item:hover{transform: scale(1.1); /* 鼠标悬停时将元素放大 1.1 倍 */ }.item{transition: transform 0.3s ease; /* 添加过渡效果&#xff0c;使过渡更加平滑 */ }

【研发日记】Matlab/Simulink避坑指南(十一)——Delay周期Bug

文章目录 前言 背景介绍 问题描述 分析排查 解决方案 总结归纳 前言 见《研发日记&#xff0c;Matlab/Simulink避坑指南(六)——字节分割Bug》 见《研发日记&#xff0c;Matlab/Simulink避坑指南(七)——数据溢出钳位Bug》 见《研发日记&#xff0c;Matlab/Simulink避坑指…

MMDetection目标检测框架推理与参数量计算

模型推理 在使用MMDetection框架完成训练后便可以使用训练所得的权重文件进行推理了&#xff0c;具体可以使用MMDetection文件下的demo文件夹的image_demo.py文件。 from argparse import ArgumentParser from mmengine.logging import print_log from mmdet.apis import Det…

CSS-IN-JS Emotion

为什么会有css-in-js 优点 缺点 使用emotion插件库 npm i emotion/core emotion/styled使用时需要解析css属性 使用方式一&#xff1a; 通过注释告诉babel不讲jsx转化为react.create Element的调用&#xff0c;而是转化为jsx语法。会导致一个警告react未使用。 使用方式二&am…

Redis__三大日志

文章目录 &#x1f60a; 作者&#xff1a;Lion J &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_69252724 &#x1f389; 主题&#xff1a;Redis__三大日志 ⏱️ 创作时间&#xff1a;2024年04月30日 ———————————————— 对于MySQL来说, 有…

ShellScript脚本编程(一)

什么是Shell Shell 是一个用 C 语言编写的程序&#xff0c;它是用户使用 Linux 的桥梁。Shell 既是一种命令语言&#xff0c;又是一种程序设计语言 Shell 是指一种应用程序&#xff0c;这个应用程序提供了一个界面&#xff0c;用户通过这个界面访问操作系统内核的服务 为什么…

Themis新篇章:老牌衍生品协议登陆Blast L2,探索全新经济模型

本文将深入分析 Themis 的最新经济模型&#xff0c;探讨其核心概念和机制、优势与创新之处、风险与挑战。 一、引言 随着区块链技术的不断发展&#xff0c;DeFi 衍生品项目逐渐成为市场的焦点。而用户体验的革新&#xff0c;进一步的金融创新&#xff0c;去中心化治理方案的优…

SpringCloud整合Gateway结合Nacos

目录 一、引入依赖 二、开启两个测试项目 2.1 order service ​编辑 2.2 user service 三、gateway项目 3.1 新建一个bootstrap.yml文件 3.2 将我们的的网关配置写道nacos里的配置里 3.3 测试&#xff1a;看能够根据网关路由到两个测试的项目 四、 优化 4.1 将项目打包…

字节跳动发起AI战争 寻找下一个TikTok

现如今在字节跳动&#xff0c;已近乎隐退的张一鸣&#xff0c;只重点关注两件事&#xff1a;其一&#xff0c;是风暴中的TikTok&#xff1b;其二&#xff0c;就是字节跳动正在全力追赶的AI战略业务。 提及字节的AI战略远望,多个接近字节的人士均认为,以Flow部门出品最为“正统…

pthread线程相关

LWP :轻量级 进程&#xff0c;本质仍是进程 进程 &#xff1a;独立地址空间&#xff0c;拥有PCB 线程&#xff1a;有独立的TCB&#xff0c;但没有独立的地址空间&#xff08;共享&#xff09; 区别 &#xff1a;在与是否共享地址文件 进程 &#xff08;独居&#xff09;&am…

数据结构:最小生成树(Prim算法和Kruskal算法)、图的最短路径(Dijkstra算法和Bellman-Ford算法)

什么是最小生成树&#xff1f;Prim算法和Kruskal算法是如何找到最小生成树的&#xff1f; 最小生成树是指在一个连通图中&#xff0c;通过连接所有节点并使得总权重最小的子图。 Prim算法和Kruskal算法是两种常用的算法&#xff0c;用于寻找最小生成树。 Prim算法的步骤如下&…

文件API及其操作

这里介绍两类文件操作、三个文件类。包括文件系统操作&#xff08;File类&#xff09;、文件内容操作&#xff08;操作字节流、操作字符流&#xff09; 1.文件类File 1.1.认识File类 &#xff08;1&#xff09;什么是File类呢&#xff1f;其实就是可以操作文件的一个类。通过…

C# dateTimePicker控件存取数据库问题

存入数据库时&#xff0c;先设置&#xff0c; dateTimePicker1.Format DateTimePickerFormat.Custom; dateTimePicker1.CustomFormat "yyyy-MM-dd HH:mm:ss"; 然后&#xff0c;dateTimePicker1.Text 就和textBox1.Text一样方式存入数据库&#xff1b;…

【Java EE】Mybatis之XML详解

文章目录 &#x1f38d;配置数据库连接和MyBatis&#x1f340;写持久层代码&#x1f338;添加mapper接口&#x1f338;添加UserInfoXMLMapper.xml&#x1f338;单元测试 &#x1f332;CRUD&#x1f338;增(Insert)&#x1f338;删(Delete)&#x1f338;改(Update)&#x1f338;…

低空经济+飞行汽车:eVTOL技术详解

低空经济是以各种有人驾驶和无人驾驶航空器的各类低空飞行活动为牵引&#xff0c;辐射带动相关领域融合发展的综合性经济形态。它广泛体现于第一、第二、第三产业之中&#xff0c;在促进经济发展、加强社会保障、服务国防事业等方面发挥着日益重要的作用。 飞行汽车&#xff0c…

Linux服务器常用命令总结

view查找日志关键词 注意日志级别&#xff0c;回车后等一会儿&#xff0c;因为文件可能比较大加载完需要时间 当内容显示出来后&#xff0c;使用“/关键词”搜索 回车就能搜到&#xff0c;n表示查找下一个&#xff0c;N表示查找上一个 find 查找 find Family -name book …

js APIS part2

什么是事件&#xff1f; 事件是在编程时系统内发生的 动作 或者发生的事情。比如用户在网页上 单击 一个按钮 什么是事件监听&#xff1f; 就是让程序检测是否有事件产生&#xff0c;一旦有事件触发&#xff0c;就立即调用一个函数做出响应&#xff0c;也称为 绑定事件或者注册…

Python爬取豆瓣电影Top250数据

任务 爬取豆瓣电影top250中的影片名称、影片海报、年份、地区、类型、评分、评价人数、总体评价&#xff0c;并输出到douban_top250.xlsx文件中 环境 Python 3.8 requests bs4 openpyxl 源码 # 创建一个新的Excel工作簿 workbook openpyxl.Workbook() # 获取默认的工作表…

酒水门店私域流量运营搭建执行规划方案

【干货资料持续更新&#xff0c;以防走丢】 酒水门店私域流量运营搭建执行规划方案 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 PPT可编辑&#xff08;完整资料包含以下内容&#xff09; 目录 精酿啤酒品牌私域执行运营的内容策划&#xff0c;涉及以下几个…

Messari 报告摘要 :Covalent Network(CQT)2024 年第一季度表现

摘要&#xff1a; 尽管 CQT 代币流通供应量增加了 20%&#xff08;新增 1.04 亿枚 CQT&#xff09;&#xff0c;但 CQT 的质押百分比仅从 2023 年第一季度的 22% 增长到了 2024 年第一季度的 29%。 CQT 的市值季度环比增长了 28%&#xff0c;多次达到 2.75 亿美元&#xff0c…