一个注解完美实现分布式锁(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.xdnf.cn/news/1419917.html

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

相关文章

小学拼音弄一下

import re from xpinyin import Pinyindef remove_middle_characters(text):# 仅保留汉字chinese_chars re.findall(r[\u4e00-\u9fff], text)cleaned_text .join(chinese_chars)# 如果字符数为偶数&#xff0c;则在中间添加空格if len(cleaned_text) % 2 0:middle_index le…

Sqlite在Mybatis Plus中关于时间字段的处理

我的个人项目中&#xff0c;使用Mybatis-Plus 和 Sqlite数据库&#xff0c; 但是在存储和查询时间字段的时候&#xff0c;总是出现问题&#xff0c;记录下我解决问题的过程。 Sqlite会默认把时间字段转成时间戳存储到数据库的字段中&#xff0c;看起来不直观&#xff0c;所以我…

鸿蒙开发-ArkTS语言-XML

鸿蒙开发-UI-web 鸿蒙开发-UI-web-页面 鸿蒙开发-ArkTS语言-基础类库 鸿蒙开发-ArkTS语言-并发 鸿蒙开发-ArkTS语言-并发-案例 鸿蒙开发-ArkTS语言-容器 鸿蒙开发-ArkTS语言-非线性容器 文章目录 前言 一、XML概述 二、XML生成 三、XML解析 1.解析XML标签和标签值 2.解析XML属性…

Mac IDEA 自动补全mybatis sql语句

导航 Mac IDEA 自动补全mybatis sql语句一、点击IDEA 右侧Database选项二、选择添加对应数据库三、输入数据库信息和方案四、输入数据库信息和方案五、成功 Mac IDEA 自动补全mybatis sql语句 背景&#xff1a; 想在Mapper中&#xff0c;能够实现自动检索数据库表和对应的字段…

安装多个版本gcc并实现快捷切换

在实际生成过程中可能需要不同gcc版本来完成编译工作。 可以在环境中配置好不同版本的gcc&#xff0c;方便快捷的实现版本的切换 linux下gcc默认保存路径&#xff1a;/usr/bin # 查看当前gcc环境 gcc --version# 查看已有的gcc包 ls /usr/bin/gcc* ls /usr/bin/g*安装特定版本…

CCF CSP 认证考试历年真题满分题解(所有前四题)

CCF CSP 认证考试历年真题满分题解&#xff08;所有前四题&#xff09; 前言 原本刷题的动机仅仅是为研究生复试的机试环节做准备&#xff0c;我通过刷csp的真题来锻炼自己&#xff0c;因为上次的机试题目全部是csp真题&#xff0c;最后也是顺利上岸。空闲之际&#xff0c;我…

Java的时间类

1. 日期类 1.1 第一代日期类 1) Date: 精确到毫秒&#xff0c;代表特定的瞬间 2) SimpleDateFormat: 格式和解析日期的类 SimpleDateFormat 格式化和解析日期的具体类。它允许进行格式化(日期-→>文本)、解析(文本->日期)和规范化. import java.text.ParseExce…

鸿蒙开发实现联系人列表(仿微信通讯录)

先看效果 直入主题 UI结构 Stack帧结构容器List联系人列表AlphabetIndexer字母索引器 实现代码 1. 先定义好假数据 通讯录列表数据 private dataList: any [{title: ,contactList: [{ name: "新的朋友", head: $r("app.media.ic_new_friend") },{ n…

CLIP 浅析

CLIP 浅析 文章目录 CLIP 浅析概述如何训练CLIP如何使用Clip进行图像分类优缺点分析优点缺点 概述 CLIP的英文全称是Contrastive Language-Image Pre-training&#xff0c;即一种基于对比文本-图像对的预训练方法或者模型。 如何训练CLIP CLIP包括两个模型&#xff1a;Text …

Web APIs - 第1天笔记

了解 DOM 的结构并掌握其基本的操作&#xff0c;体验 DOM 的在开发中的作用 知道 ECMAScript 与 JavaScript 的关系 了解 DOM 的相关概念及DOM 的本质是一个对象 掌握查找节点的基本方法 掌握节点属性和文本的操作 能够使用间歇函数创建定时任务 介绍 知道 ECMAScript 与…

ok_Keil实用小技巧 | Keil定制Hex文件名实现的方法

Keil实用小技巧 | Keil定制Hex文件名实现的方法 echo off REM 可执行文件&#xff08;Hex&#xff09;文件名 set HEX_NAMEDemo REM 可执行文件&#xff08;Hex&#xff09;文件路径 set HEX_PATH.\Objects REM 定制Hex输出路径 set OUTPUT_PATH.\Output REM 软件版本文件…

答辩PPT不会做?试试这些AI工具,一键生成

在我原本的认知里面&#xff0c;答辩PPT是要包含论文各个章节的&#xff0c;在答辩时需要方方面面都讲到的&#xff0c;什么摘要、文献综述、实证分析、研究结果样样不落。但是&#xff0c;这大错特错&#xff01; 答辩PPT环节时长一般不超过5分钟&#xff0c;老师想要的答辩P…

解读丰田生产方式的工作原理

丰田生产方式&#xff0c;被誉为现代制造业的瑰宝&#xff0c;以其独特的精益生产理念&#xff0c;引领了全球制造业的变革。本文将从丰田生产方式的核心理念、两大支柱、应用实践以及面临的挑战等方面&#xff0c;全面解读其工作原理。 丰田生产方式&#xff0c;又称精益生产&…

数据库调优-连接池优化

先贴下连接池的相关配置&#xff1a; 连接池参数配置&#xff1a; 字段含义Max Number of Connections最大连接数&#xff1b;做性能测试时&#xff0c;可以填 0 。在开发的项目中按实际代码填写&#xff0c;默认是 20 。Max Wait(ms)在连接池中取回连接最大等待时间&#xf…

在 Navicat 17 创建一个数据字典

即将于 5 月 13 日发布的 Navicat 17&#xff08;英文版&#xff09;添加了许多令人兴奋的新功能。其中之一就是数据字典工具。它使用一系列 GUI 指导你完成创建专业质量文档的过程&#xff0c;该文档为跨多个服务器平台的数据库中的每个数据元素提供描述。在今天的博客中&…

基于springboot+vue+Mysql的外卖点餐系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

嵌入式基础课程配套电机FOC伺服电机开发板AT32F403磁编码IMU姿态

嵌入式基础课程配套电机FOC伺服电机开发板AT32F403磁编码IMU姿态 带你入门嵌入式有二十多年开发经验的老技骨做技术支持整个开发包硬件包括电机2205&#xff0c;支持12V到24V宽输入&#xff0c;配套12V2A电源。包装原理图和PCB嵌入式软件嵌入式基础课程 带你入门嵌入式 电机FO…

瀚高数据库(HighGoDB)Windows安装使用

1.下载 2.安装 瀚高数据库下载与安装&#xff08;Windows版&#xff09;-CSDN博客 3.连接工具 4.建库、建表操作 瀚高数据库管理工具-CSDN博客 *报错Cant access non-default database&#xff0c;需要右键数据库-设为活动对象 5.导入外部数据&#xff08;迁移、对比&…

多模态CLIP和BLIP

一、CLIP 全称为Contrastive Language-Image Pre-Training用于做图-文匹配&#xff0c;部署在预训练阶段&#xff0c;最终理解为图像分类器。 1.背景 以前进行分类模型时&#xff0c;存在类别固定和训练时要进行标注。因此面对这两个问题提出CLIP&#xff0c;通过这个预训练…

2024年4月12日饿了么春招实习试题【第二题:魔法师】-题目+题解+在线评测【二分】

2024年4月12日饿了么春招实习试题【第二题:魔法师】-题目题解在线评测【二分】 题目描述&#xff1a;输入格式输出格式样例输入样例输出评测数据与规模 解题思路一&#xff1a;解题思路二&#xff1a;解题思路三&#xff1a;动态规划 题目描述&#xff1a; 塔子哥是一名魔法师…