SpringBoot分布式锁自定义注解处理幂等性

SpringBoot分布式锁+自定义注解处理幂等性

注解简介

注解(Annotation)是Java SE 5.0 版本开始引入的概念,它是对 Java 源代码的说明,是一种元数据(描述数据的数据)。

Java中的注解主要分为以下三类:

JDK的注解
第三方的注解
自定义注解

JDK注解

Java内置注解@Override (标记重写方法)@Deprecated (标记过时)@SuppressWarnings (忽略警告)
元注解 (注解的注解)@Target (注解的作用目标)@Retention (注解的生命周期)@Document (注解是否被包含在JavaDoc中)@Inherited (是否允许子类集成该注解)
@Target

用于描述注解的使用范围,有一个枚举ElementType来指定,具体如下:

Target类型描述
ElementType.TYPE应用于类、接口(包括注解类型)、枚举
ElementType.FIELD应用于属性(包括枚举中的常量)
ElementType.METHOD应用于方法
ElementType.PARAMETER应用于方法的形参
ElementType.CONSTRUCTOR应用于构造函数
ElementType.LOCAL_VARIABLE应用于局部变量
ElementType.ANNOTATION_TYPE应用于注解类型
ElementType.PACKAGE应用于包
ElementType.TYPE_PARAMETER应用于类型变量
ElementType.TYPE_USE应用于任何使用类型的语句中(例如声明语句、泛型和强制转换语句中的类型)
@Retention

表示需要在什么级别保存该注释信息,用于描述注解的生命周期,也是一个枚举RetentionPoicy来决定的

取值含义
RetentionPolicy.SOURCE源码中保留,编译期可以处理
RetentionPolicy.CLASSClass文件中保留,Class加载时可以处理
RetentionPolicy.RUNTIME运行时保留,运行中可以处理

一般填RetentionPoicy.RUNTIME即可

@Documented

如果用javadoc生成文档时,想把注解也生成文档,就带这个。

@Inherited

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。注意,@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

自定义注解

使用JDK中一些元注解,@Target,@Retention,@Document,@Inherited来修饰注解。具体格式如下:
在这里插入图片描述

自定义注解实例:

import org.springblade.core.redis.lock.LockType;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;/*** 分布式锁注解处理幂等性* 分布式锁注解,Redisson,支持的锁的种类有很多,适合注解形式的只有重入锁、公平锁** <p>* 1. 可重入锁(Reentrant Lock)* 2. 公平锁(Fair Lock)* 3. 联锁(MultiLock)* 4. 红锁(RedLock)* 5. 读写锁(ReadWriteLock)* </p>*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface RedisIdempotentLock {/*** 分布式锁的 key,必须:请保持唯一性** @return key*/String prefix() default "";/*** 分布式锁参数,可选,支持 spring el # 读取方法参数和 @ 读取 spring bean** @return param*/String param() default "";/*** 使用用户id作为新增等接口作为唯一key,处理幂等** @return param*/boolean isUserId() default false;/*** 等待锁超时时间,默认30** @return int*/long waitTime() default 30;/*** 自动解锁时间,自动解锁时间一定得大于方法执行时间,否则会导致锁提前释放,默认-1** @return int*/long leaseTime() default -1;/*** 时间单温,默认为秒** @return 时间单位*/TimeUnit timeUnit() default TimeUnit.SECONDS;/*** 默认公平锁** @return LockType*/LockType type() default LockType.FAIR;}

AOP 切面通用分布式锁+自定义注解处理幂等性;

import com.zhkj.ims.anotation.RedisIdempotentLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.redis.lock.LockType;
import org.springblade.core.redis.lock.RedisLockClient;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.spel.BladeExpressionEvaluator;
import org.springblade.core.tool.utils.CharPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;/*** redis 分布式锁处理幂等性*/
@Aspect
@Component
public class RedisIdempotentLockAspect implements ApplicationContextAware {private static final Logger LOGGER = LoggerFactory.getLogger(RedisIdempotentLockAspect.class);/*** 表达式处理*/private static final BladeExpressionEvaluator EVALUATOR = new BladeExpressionEvaluator();@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate RedisLockClient redisLockClient;@Autowiredprivate ApplicationContext applicationContext;private static final String DEFAULT_SUPER_PREFIX = "idempotence";/*** AOP 环切 注解 @RedisIdempotentLock*/@Around(value = "@annotation(redisIdempotentLock)")public Object aroundRedisLock(ProceedingJoinPoint point, RedisIdempotentLock redisIdempotentLock) throws Throwable {String prefix = redisIdempotentLock.prefix();Class clazz = point.getTarget().getClass();String methodName = point.getSignature().getName();String lockName;String fullClassName = clazz.getName();if (StringUtils.hasText(fullClassName)) {String[] splits = fullClassName.split("\\.");String className = splits[splits.length - 1];lockName = className + CharPool.COLON + methodName;} else {lockName = methodName;}lockName = StringUtils.hasText(prefix) ? DEFAULT_SUPER_PREFIX + CharPool.COLON + prefix + CharPool.COLON + lockName : DEFAULT_SUPER_PREFIX + CharPool.COLON + lockName;String lockParam = redisIdempotentLock.param();String lockKey;if (StringUtil.isNotBlank(lockParam)) {// 解析表达式String evalAsText = evalLockParam(point, lockParam);lockKey = lockName + CharPool.COLON + evalAsText;if (redisIdempotentLock.isUserId()) {lockKey = lockKey + CharPool.COLON + AuthUtil.getUserId();}} else {if (redisIdempotentLock.isUserId()) {lockKey = lockName + CharPool.COLON + AuthUtil.getUserId();} else {lockKey = lockName;}}LockType lockType = redisIdempotentLock.type();long waitTime = redisIdempotentLock.waitTime();long leaseTime = redisIdempotentLock.leaseTime();TimeUnit timeUnit = redisIdempotentLock.timeUnit();Object result;boolean release = false;if (existKey(lockKey)) {throw new ServiceException("操作进行中,请稍后重试!");}try {boolean tryLock = redisLockClient.tryLock(lockKey, lockType, waitTime, leaseTime, timeUnit);if (tryLock) {release = true;result = point.proceed();} else {throw new ServiceException("操作进行中,请稍后重试!");}} catch (Exception e) {LOGGER.info("方法处理异常:{}", e.getMessage());throw e;} finally {if (release && existKey(lockKey)) {LOGGER.info("释放锁key:{}", lockKey);redisLockClient.unLock(lockKey, lockType);}}return result;}/*** 计算参数表达式** @param point     ProceedingJoinPoint* @param lockParam lockParam* @return 结果*/private String evalLockParam(ProceedingJoinPoint point, String lockParam) {MethodSignature ms = (MethodSignature) point.getSignature();Method method = ms.getMethod();Object[] args = point.getArgs();Object target = point.getTarget();Class<?> targetClass = target.getClass();EvaluationContext context = EVALUATOR.createContext(method, args, target, targetClass, applicationContext);AnnotatedElementKey elementKey = new AnnotatedElementKey(method, targetClass);return EVALUATOR.evalAsText(lockParam, elementKey, context);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}private boolean existKey(String lockKey) {Assert.hasText(lockKey, "lockKey must not null.");return redisTemplate.hasKey(lockKey);}
}

​ 具体使用

@RestController
public class TestController {@Autowiredprivate JdbcConfig jdbcConfig;@RedisIdempotentLock(param = "#id")@PostMapping("/hello")public String Hello(Long id) {return jdbcConfig.getUrl() + "  " + jdbcConfig.getDriver() + " " + jdbcConfig.getUser() + " " + jdbcConfig.getPassword();}
}

{

@Autowired
private JdbcConfig jdbcConfig;

@RedisIdempotentLock(param = “#id”)
@PostMapping(“/hello”)
public String Hello(Long id) {
return jdbcConfig.getUrl() + " " + jdbcConfig.getDriver() + " " + jdbcConfig.getUser() + " " + jdbcConfig.getPassword();
}
}

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

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

相关文章

如何制作透明文件夹?

哇&#xff01;是不是很羡慕&#xff1f; 保姆级教程来啦&#xff01; 我们先新建一个文件夹 这么辛苦写文章&#xff0c;可以给我点个关注么~

C++ —— C++11新增语法

目录 一&#xff0c;列表初始化 1.1 这是什么&#xff1f; 1.2 initializer_list 1.3 在容器的运用 1.4 STL中的变化 二&#xff0c;右值引用和左值引用 2.1 是什么&#xff1f; 2.2 这两个东西有啥关系&#xff1f; 2.3 有啥用&#xff1f; 三&#xff0c;*移动构…

20232831 2023-2024-2 《网络攻防实践》第4次作业

目录 20232831 2023-2024-2 《网络攻防实践》第4次作业1.实验内容2.实验过程&#xff08;1&#xff09;ARP缓存欺骗攻击&#xff08;2&#xff09;ICMP重定向攻击&#xff08;3&#xff09;SYN Flood攻击&#xff08;4&#xff09;TCP RST攻击&#xff08;5&#xff09;TCP会话…

图片标注编辑平台搭建系列教程(4)——fabric几何定制渲染

背景 标注的几何&#xff0c;有时需要一些定制化的渲染样式&#xff0c;例如&#xff0c;线中间展示箭头&#xff0c;表示方向。本期教程教大家如何实现fabric几何定制化渲染。 带箭头的线 fabric提供了一些原生的几何&#xff0c;例如Point、Polyline、Polygon。同时提供了…

简易挛生分拣系统设计

1 工效组合展示 2 方案规划设计 3 数字挛生建模 基础建模、动画设计、模型导出 4 软件体系架构 5 Web交互设计 5.1 页面架构 5.2 初始构造 5.3 模型运用 5.4 WS通信 5.5 运行展现 6 服务支撑编码 6.1 整体调度 6.2 WS服务 6.3 C/S通信 7 系统级调试完善

政安晨:专栏目录【TensorFlow与Keras机器学习实战】

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 本篇是作者政安晨的专栏《TensorFlow与Keras机器…

k8s-jenkins安装与流水线

k8s-jenkins安装与流水线 一、环境安装1.创建目录2.后台启动服务3.浏览器访问4.修改密码 二、流水线1.新建流水线任务2.运行流水线3.安装插件4.安装Kubernetes CLI 三、总结 一、环境安装 如果使用的是阿里云Kubernetes集群 &#xff0c;可以安装其 ack-jenkins应用。 5分钟在…

Qt篇——Qt无法翻译tr()里面的字符串

最近遇到使用Qt语言家翻译功能时&#xff0c;ui界面中的中文都能够翻译成英文&#xff0c;但是tr("测试")这种动态设置给控件的中文&#xff0c;无法翻译&#xff08;lang_English.ts文件中的翻译已经正确添加了tr()字符串的翻译&#xff09;。 上网搜了很多资料&am…

Docker命令及部署Java项目

文章目录 简介Docker镜像镜像列表查找镜像拉取镜像删除镜像镜像标签 Docker容器容器启动容器查看容器停止和重启后台模式和进入强制停止容器清理停止的容器容器错误日志容器别名及操作 Docker部署Java项目 简介 Docker是一种容器化技术&#xff0c;可以帮助开发者轻松打包应用…

芒果YOLOv8改进145:全新风格原创YOLOv8网络结构解析图

&#x1f4a1;本篇分享一下个人绘制的原创全新风格 YOLOv8网络结构图 感觉搭配还行&#xff0c;看着比较直观。 该专栏完整目录链接&#xff1a; 芒果YOLOv8深度改进教程 订阅了专栏的读者 可以获取一份 <可以自行修改 / 编辑> 的 YOLOv8结构图修改源文件 YOLOv8结构图…

spring多线程实现+合理设置最大线程数和核心线程数

1.最简单的方法&#xff1a; 需要在 Spring Boot 主类上添加 EnableAsync 注解启用异步功能&#xff1b;需要在异步方法上添加 Async 注解。 示例代码如下&#xff1a; SpringBootApplication EnableAsync public class Application {public static void main(String[] args…

网络爬虫框架Scrapy的入门使用

Scrapy的入门使用 Scrapy概述引擎&#xff08;Engine&#xff09;调度器&#xff08;Scheduler&#xff09;下载器&#xff08;Downloader&#xff09;SpiderItem Pipeline 基本使用安装scrapy创建项目定义Item数据模型对象创建爬虫(Spider)管道pipeline来保存数据启动爬虫 其他…

什么是拧紧扭矩——SunTorque智能扭矩系统

智能扭矩系统-智能拧紧系统-扭矩自动控制系统-SunTorque 拧紧扭矩是紧固件&#xff08;如螺栓、螺母等&#xff09;在拧紧过程中施加在螺纹上的力矩&#xff0c;用于使紧固件产生预紧力&#xff0c;从而保证连接的可靠性和安全性。拧紧扭矩是紧固件连接中非常重要的一个参数&a…

数据更新了,vue的界面没有更新?大写的why到底是为什么!!!

最近工作中&#xff0c;遇见了两个小问题&#xff0c;一时没有反应过来&#xff0c;特此写博客记录一下。希望下次秒反应&#xff01;&#xff01; 有一个界面&#xff0c;打开的时候&#xff0c;由于界面显示内容过多导致而出现了滚动条。第一次浏览窗口时&#xff0c;移动了滚…

qt完成对话框提示

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//去掉头部this->setWindowFlag(Qt::FramelessWindowHint);//去掉空白this->setAttribute(Qt::WA_Transl…

HTML input 实现回车切换到下一个输入框功能

前言 遇到需求&#xff0c;在客户填写单子时&#xff0c;有多个输入框&#xff0c;为了省事&#xff0c;不需要频繁移动光标填写。 实现效果 实现方式一 HTML <input type"text" name"serialNumber1" onkeydown"cursor(this);"/><in…

是谁?阻止CXL在AI场景大展身手~

CXL虽然被视为业内新宠&#xff0c;但好像在AI场景的应用反而没有得到广泛的响应。 AI场景对内存带宽、容量以及数据一致性有着极高需求&#xff0c;特别是在深度学习训练和推理过程中&#xff0c;大量数据需要在CPU、GPU、加速器以及内存之间快速、高效地流动。CXL作为一种新…

ForkJoinPool、CAS原子操作

ForkJoinPool ForkJoinPool是由JDK1.7后提供多线程并行执行任务的框架。可以理解为一种特殊的线程池。 1.任务分割&#xff1a;Fork&#xff08;分岔&#xff09;&#xff0c;先把大的任务分割成足够小的子任务&#xff0c;如果子任务比较大的话还要对子任务进行继续分割。 …

内网靶机~~dc-2

一、信息收集 1.端口扫描&#xff1a; nmap -sV -p 1-10000 10.1.1.4 2.CMS识别 3.目录扫描&#xff1a; dirsearch http://10.1.1.4/ 4.FLAG1 似乎让我们用cewl生成密码字典&#xff0c;并爆破登录。 cewl -w rewl_passwd.txt http://dc-2/index.php/flag/ 总结&#xff…

离线Linux/openEuler服务器指定本地yum仓库

1、前提准备一个预装坏境比较完整的linux镜像文件&#xff0c;本文服务器使用的是openEuler 官网&#xff1a;openEuler下载 | 欧拉系统ISO镜像 | openEuler社区官网 2、上传镜像文件至服务器 如果是集群服务器&#xff0c;上传其中一台服务器之后&#xff0c;使用scp指令将镜…