分布式锁注解SyncLock

一、目标:

                1、简化手动开关锁的重复代码(专注业务本身)

                2、集成不同分布式锁解决方案(锁不同使用方式不同)

                3、规范锁的命名和异常信息内容(内容不规范,不易于理解和维护)

                4、避免事务大于锁的优先级,造成幻读(事务和锁使用不熟)

二、基本需求:

              锁的命名、异常信息、锁等待时间、快速失败、异常是否抛出

三、设计思想:

                 通过springAOP和order注解在方法上切入解决事务和锁的优先级,提供统一开关锁接口loackManager集成不同分布式锁作为锁管理器,使用springEL表达式规范锁的命名和异常信息内容

四、常规分布式锁实现方案

1、内存容器(单机),如concurrentHashMap

2、spring提供的(支持集群)

jdbc-lock-registry、redis-lock-registry、zk-lock-registry

五、代码实现:(目前暂实现concurrentHashMap和redis,如有需要自己拓展)

/*** @description: DistributionLock <br>* 建议:'领域对象:对象行为:'+#业务参数;层级前加:(redis结构清晰),参数前#(spel语法)* @SyncLock(key = "'branchCompany:cece:' + #dto.diposeOrgId, lockManager =* "redis")* @date: 2023/01/15 15:26 <br>* @author: arthur<br>* @version: 1.0 <br>*/
@Target({METHOD})
@Retention(RUNTIME)
public @interface SyncLock {/*** 锁管理器** @return 锁管理器*/String lockManager() default "jvm";/*** SpEL表达式支持** @return SpEL表达式*/String key();/*** SpEL表达式支持** @return SpEL表达式*/String errorMsg() default "";/*** 快速失败** @return 快速失败*/boolean fastFail() default false;/*** 锁等待时间(单位:秒,默认10S)** @return 锁等待时间*/long waitTime() default 10;/*** 异常是否抛出** @return 默认true*/boolean throwError() default true;
}
/*** @description: LockManager <br>* @date: 2023/01/15 15:26 <br>* @author: arthur<br>* @version: 1.0 <br>*/
public interface LockManager {Lock getLock(String lockName);
}/*** @description: JvmLockManager <br>* @date: 2023/01/15 15:26 <br>* @author: arthur<br>* @version: 1.0 <br>*/
public class JvmLockManager implements LockManager {private final Map<String, Lock> cache = new ConcurrentHashMap<>();@Overridepublic Lock getLock(String lockName) {return cache.computeIfAbsent(lockName, k -> new ReentrantLock());}
}/*** @description: RedissionLockManager <br>* @date: 2023/01/15 15:26 <br>* @author: arthur<br>* @version: 1.0 <br>*/
@Component
@RequiredArgsConstructor
public class RedisLockManager implements LockManager {private final RedissonClient redissonClient;@Overridepublic Lock getLock(String lockName) {return redissonClient.getLock(lockName);}
}
/*** @description: DistributionLockAspect <br>* @date: 2023/01/15 15:26 <br>* @author: arthur<br>* @version: 1.0 <br>*/
@Slf4j
@Aspect
@RequiredArgsConstructor
@Order(1)
public class SyncLockAspect implements InitializingBean, ApplicationContextAware {private final ExpressionParser parser = new SpelExpressionParser();private final LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();private ApplicationContext context;private final Map<String, LockManager> lockManagerMap = new HashMap<>();@Pointcut(value = "@annotation(com.runlion.hshb.common.lock.annotation.SyncLock)")public void SyncLock() {}@Around("SyncLock() && @annotation(syncLock)")public Object inject(ProceedingJoinPoint pjp, SyncLock syncLock) throws Throwable {Signature s = pjp.getSignature();MethodSignature ms = (MethodSignature) s;Method method = ms.getMethod();String lockKey = parseSpel(method, pjp.getArgs(), syncLock.key());LockManager lockManager = lockManagerMap.get(syncLock.lockManager());if (null == lockManager) {log.warn("未获取到同步锁管理器:{}", syncLock.lockManager());return pjp.proceed();}Lock lock = lockManager.getLock(lockKey);boolean getLock;//是否快速失败if (syncLock.fastFail()) {getLock = lock.tryLock();} else {getLock = lock.tryLock(syncLock.waitTime(), TimeUnit.SECONDS);}//判断是否获取到锁if (getLock) {try {return pjp.proceed();} finally {lock.unlock();}} else if (syncLock.throwError()) {if (StringUtils.isNotBlank(syncLock.errorMsg())) {throw new IllegalArgumentException(parseSpel(method, pjp.getArgs(), syncLock.errorMsg()));} else {throw new IllegalArgumentException("无法获取分布式锁[" + lockKey + "]");}} else {log.info("无法获取lockKey::  {}", lockKey);return null;}}private String parseSpel(Method method, Object[] arguments, String spelExpression) {String[] params = discoverer.getParameterNames(method);assert params != null;EvaluationContext context = new StandardEvaluationContext();for (int len = 0; len < params.length; len++) {context.setVariable(params[len], arguments[len]);}try {Expression expression = parser.parseExpression(spelExpression);return expression.getValue(context, String.class);} catch (Exception e) {return spelExpression;}}@Overridepublic void afterPropertiesSet() {Map<String, LockManager> managerMap = this.context.getBeansOfType(LockManager.class);for (Map.Entry<String, LockManager> entry : managerMap.entrySet()) {this.lockManagerMap.put(StringUtils.removeEnd(entry.getKey(), "LockManager"), entry.getValue());}log.info("已安装同步锁管理器:{}", this.lockManagerMap.keySet());}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.context = applicationContext;}
}
/*** @description: DistributionLockAutoConfiguration <br>* @date: 2023/01/15 15:26 <br>* @author: arthur<br>* @version: 1.0 <br>*/
@Configuration
public class SyncLockAutoConfiguration {@Beanpublic SyncLockAspect syncLockAspect() {return new SyncLockAspect();}@Beanpublic JvmLockManager jvmLockManager() {return new JvmLockManager();}@Configuration@ConditionalOnProperty(prefix = "lock", value = "distributed", havingValue = "true")@Import({CacheConfiguration.class})@AutoConfigureAfter({CacheConfiguration.class})public static class DistributionLockConfiguration {@Beanpublic RedisLockManager redisLockManager(RedissonClient redissonClient) {return new RedisLockManager(redissonClient);}}
}

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

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

相关文章

pyspark笔记:over

1 方法介绍 在 PySpark 中&#xff0c;over 函数是一个非常重要的概念&#xff0c;尤其是在使用窗口函数&#xff08;例如 row_number, rank, dense_rank, lead, lag 等&#xff09;时。over 函数允许你对一个数据集进行分组&#xff0c;然后在每个分组内应用窗口函数。 1.1 …

Appium 环境配置

Appium 是一个开源的、跨平台的测试框架&#xff0c;可以用来测试 Native App、混合应用、移动 Web 应用&#xff08;H5 应用&#xff09;等&#xff0c;也是当下互联网企业实现移动自动化测试的重要工具。Appium 坚持的测试理念&#xff1a; •无需用户对 App 进行任何修改或…

2024年一整年的考试报名时间表不许再错过考试啦

每个大学生都不能错过的超全考试报名表&#xff01; 有了它谁还会再错过考试哇&#xff01;&#xff01;&#xff01; 1月报名 专转本考试 12月底-1月报名 卫生资格考试 1月中旬报名 教师资格证笔试 1月报名 各省省考 2月报名 医师资格考试 2月报名 初级高级会计 2月报名 计算机…

Java 基础 - Java 多态性详解与实例解析

Java 多态性详解与实例解析 多态性是面向对象编程中的一个重要概念,它允许不同类型的对象以相同的方式对待,从而提高了代码的灵活性和可维护性。在 Java 中,多态性通过继承和方法重写实现,让我们深入了解一下。 什么是多态性? 多态性是指在同一类型的变量调用相同方法时…

架构篇05-复杂度来源:高可用

文章目录 计算高可用存储高可用高可用状态决策小结 今天&#xff0c;我们聊聊复杂度的第二个来源高可用。 参考维基百科&#xff0c;先来看看高可用的定义。 系统无中断地执行其功能的能力&#xff0c;代表系统的可用性程度&#xff0c;是进行系统设计时的准则之一。 这个定义…

快速入门:使用 Gemini Embeddings 和 Elasticsearch 进行向量搜索

Gemini 是 Google DeepMind 开发的多模态大语言模型家族&#xff0c;作为 LaMDA 和 PaLM 2 的后继者。由 Gemini Ultra、Gemini Pro 和 Gemini Nano 组成&#xff0c;于 2023 年 12 月 6 日发布&#xff0c;定位为 OpenAI 的竞争者 GPT-4。 本教程演示如何使用 Gemini API 创建…

【代码整理】基于COCO格式的pytorch Dataset类实现

import模块 import numpy as np import torch from functools import partial from PIL import Image from torch.utils.data.dataset import Dataset from torch.utils.data import DataLoader import random import albumentations as A from pycocotools.coco import COCO …

java SSM园林绿化管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM园林绿化管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…

网易真的大规模裁员吗?

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 以前互联网公司裁员&#xff0c;大家不紧张&#xff0c;因为容易找工作&#xff0c;而现在不知道怎么回事&#xff0c;只要以提高某某公司裁员&#xff0c;这就能迅速登上热榜。 这不&#xff0c;最近网传网易裁员1…

二、项目开发计划模板

1&#xff0e;引言 1.1编写目的 1.2项目背景 1.3定义 1.4参考资料 2&#xff0e;项目概述 2.1工作内容 2.2条件与限制 2.3产品 2.4运行环境 2.5服务 2.6验收标准 3&#xff0e;实施计划 3.1任务分解 3.2进度 3.3预算 3.4关键问题 4&#xff…

Linux的IO文件操作和文件系统

前要&#xff1a;本次我想给您带来关于 IO 和文件的知识&#xff0c;而文件在本系列中分为内存上的文件和磁盘上的文件。 1.文件概念 1.1.文件读写 在谈及系统接口之前&#xff0c;我们先来从 C 语言的角度来谈及一些前要知识&#xff0c;以辅助我们后续来理解系统 IO。 我们…

大数据导论(3)---大数据技术

文章目录 1. 大数据技术概述2. 数据采集与预处理2.1 数据采集2.2 预处理 3. 数据存储和管理3.1 分布式基础架构Hadoop3.2 分布式文件系统HDFS3.3 分布式数据库HBase3.4 非关系型数据库NoSQL 4. 数据可视化与保护 1. 大数据技术概述 大数据技术主要包括数据采集与预处理、数据存…

关于常见分布式组件高可用设计原理的理解和思考

文章目录 1. 数据存储场景和存储策略1.1 镜像模式-小规模数据1.2 分片模式-大规模数据 2. 数据一致性和高可用问题2.1 镜像模式如何保证数据一致性2.2 镜像模式如何保证数据高可用2.2.1 HA模式2.2.2 分布式选主模式 2.3 分片模式如何数据一致性和高可用 3. 大规模数据集群的架构…

32 登录页组件

效果演示 实现了一个登录页面的样式&#xff0c;包括一个容器、左侧和右侧部分。左侧部分是一个背景图片&#xff0c;右侧部分是一个表单&#xff0c;包括输入框、复选框、按钮和忘记密码链接。整个页面的背景色为白色&#xff0c;容器为一个圆角矩形&#xff0c;表单为一个半透…

linux C语言socket函数send

在Linux中&#xff0c;使用C语言进行网络编程时&#xff0c;send函数是用于发送数据到已连接的套接字的重要函数之一。它通常用于TCP连接&#xff0c;但也可以用于UDP&#xff08;尽管对于UDP&#xff0c;通常更推荐使用sendto&#xff0c;因为它允许你指定目标地址和端口&…

建议数据库设计的必选字段

在数据库设计时&#xff0c;建议以下13个字段设置为数据库必要字段&#xff0c;以保证数据的完整和连续。&#xff08;参考阿里开发规范&#xff0c;结合业务特点&#xff09; id&#xff08;id&#xff09; id 是否删除&#xff08;if_delete&#xff09; 用于表达该记录是…

vivado 平台板流程

介绍 板文件使用XML格式来定义有关使用或的系统级板的信息包括AMD设备。AMD可以使用板文件中包含的信息Vivado™ Design Suite和Vivado IP集成商&#xff0c;以促进和验证AMD的连接设备到板。本章讨论董事会文件的不同部分及其用法本附录中所示的示例使用AMD Kintex 7 KC705评…

【linux驱动】用户空间程序与内核模块交互-- IOCTL和Netlink

创建自定义的IOCTL&#xff08;输入/输出控制&#xff09;或Netlink命令以便用户空间程序与内核模块交互涉及几个步骤。这里将分别介绍这两种方法。 一、IOCTL 方法 1. 定义IOCTL命令 在内核模块中&#xff0c;需要使用宏定义你的IOCTL命令。通常情况下&#xff0c;IOCTL命令…

python 基础知识点(蓝桥杯python 科目个人复习计划22)

今日复习内容&#xff1a;基础算法中的时间复杂度 时间复杂度分析 时间复杂度是衡量算法执行时间随输入规模增长的增长率。通过分析算法中基本操作的执行次数来确定时间复杂度‘常见的时间复杂度包括&#xff1a;常数时间O(1)&#xff0c;线性时间O(n),对数时间O(log n)&…

[GN] Vue3.2 快速上手 ---- 核心语法(终章)_3

文章目录 路由器工作模式命名路由to的三种写法嵌套路由路由传参query参数params参数 路由的props配置replace 和 push编程式导航重定向 总结 路由器工作模式 history模式 优点&#xff1a;URL更加美观&#xff0c;不带有#&#xff0c;更接近传统的网站URL。 缺点&#xff1a;后…