【接口防重复提交】⭐️基于RedisLockRegistry 分布式锁管理器实现

目录

前言

思路

实现方式

实践

        1.引入相关依赖

        2.aop注解

        3.切面类代码

        4.由于启动时报错找不到对应的RedisLockRegistry bean,选择通过配置类手动注入,配置类代码如下

 测试

 章末


前言

        项目中有个用户根据二维码绑定身份的接口,由于用户在操作时,可能会因为网络延迟或者其他原因多次点击提交按钮,导致重复提交相同的请求,所以需要在一定时间内限制同一个用户相同操作的重复提交,避免重复绑定的情况发生

思路

        通过Spring 的aop 功能加上分布式锁实现,aop功能可以实现切面操作有关接口,再通过分布式锁实现同一个请求在一段时间内只执行一次,保证操作的幂等性,避免数据异常

实现方式

        分布式锁选择的是 RedisLockRegistry,下面是该锁的简单介绍

RedisLockRegistry 是 Spring Integration 提供的一个基于 Redis 实现的分布式锁实用程序。可以用于在分布式环境中实现对共享资源的互斥访问。

RedisLockRegistry 使用 Redis 的原子性操作和过期时间设置来实现分布式锁。通过在 Redis 中创建一个特定的键(key),并在获取锁时将该键设置为具有过期时间的值(value)。其他线程或进程通过尝试在同一键上执行相同操作,如果能够设置成功,则表示获取到了锁,可以执行操作;否则,表示锁被其他线程或进程占用,需要等待。

实践

        1.引入相关依赖

		<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-integration</artifactId></dependency><dependency><groupId>org.springframework.integration</groupId><artifactId>spring-integration-redis</artifactId></dependency>

        2.aop注解

        这里有两个方法,一个是提供获取锁可重试时常,另一个是获得指定的key

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/** 防止重复提交,通过分布式锁,限制同一个api接口并发时多次重复提交* @author ben.huang*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AntiReplay {/*** 获取锁重试时间,默认0ms,也就是不许重试,加锁失败,立即返回* 产生竞争时,重试获取锁的最长等待时间,在改时间内如果没有获取到锁,则失败* @return*/int tryLockTime() default 0;/*** 自定义的Key,不填的话默认“”,代码中可以自定义拼接*  需要自己提供默认的话,在注解使用时赋值即可* @return*/String key() default "";
}

        3.切面类代码

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;/*** @author ben.huang*/
@Component
@Aspect
@Slf4j
public class AntiReplayAspect {@Resourceprivate RedisLockRegistry redisLockRegistry;@Pointcut("@annotation(antiReplay)")public void pointcut(AntiReplay antiReplay){}@Around(value = "pointcut(antiReplay)")public Object around(ProceedingJoinPoint proceedingJoinPoint,AntiReplay antiReplay) throws Throwable{int tryLockTime = antiReplay.tryLockTime();Object result = null;String name = "testRedisLock-";String path = antiReplay.key();//这里简化了,使用时可以使用用户唯一辨识(比如用户id)拼接keyString key = name + path;Lock lock = redisLockRegistry.obtain(key);boolean isSuccess = lock.tryLock(tryLockTime, TimeUnit.MILLISECONDS);if(isSuccess){log.info("获取锁 key = [{}]",key);try{result = proceedingJoinPoint.proceed();}finally{if(isSuccess){lock.unlock();log.info("释放锁 success, key = [{}]",key);}}}else{log.info("获取锁失败 fial ,key = [{}]",key);throw new Exception("error");}return result;}
}

        4.由于启动时报错找不到对应的RedisLockRegistry bean,选择通过配置类手动注入,配置类代码如下

Description: A component required a bean of type 'org.springframework.integration.redis.util.RedisLockRegistry' that could not be found.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.integration.redis.util.RedisLockRegistry;/*** @author ben.huang*/
@Configuration
public class AntiReplayConfig {@Beanpublic RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory){RedisLockRegistry redisLockRegistry = new RedisLockRegistry(redisConnectionFactory, "my-lock-key");return redisLockRegistry;}}

 测试

        1.因为该场景是在并发时发生的,所以可以选择压测的方式模拟下并发场景,创建一个简单的测试接口,登录成功则在控制台打印信息,否则抛出异常

    @AntiReplay(key = "userLogin")@PostMapping(value = "/login")public BaseResult login(String username, String password) {UserEntity user = userService.selectOne(new EntityWrapper<UserEntity>().eq("username", username));if(user==null || !user.getPassword().equals(password)) {throw new RuntimeException("error while logining");}System.out.println(" login success!");return BaseResult.success();}

         2.压测工具使用的是APIpost接口测试工具,不加防重复注解时启动项目调用接口的结果如下

可以看到在没有加锁的情况下,所有请求全部成功

        3.加上注解后再次压测,结果如下 ,可以看到大部分请求都失败了,为什么还有这么多请求成功的?是因为获取到锁的线程会释放锁,后面的线程还可以接着抢,看控制台也会发现有很多次释放锁记录

 章末

        文章到这里就结束了~

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

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

相关文章

【Unity动画】Unity如何导入序列帧动画(GIF)

Unity 不支持GIF动画的直接播放&#xff0c;我们需要使用序列帧的方式 01准备好序列帧 02全部拖到Unity 仓库文件夹中 03全选修改成精灵模式Sprite 2D ,根据需要修改尺寸&#xff0c;点击Apply 04 创建一个空物体 拖动序列上去 然后全选所有序列帧&#xff0c;拖到这个空物体…

SpringBoot中使用验证码easy-captcha

easy-captcha使用的大概逻辑: 当一个请求发送到后端服务器请求验证,服务器使用easy-captcha生成一个验证码图片,并通过session将验证信息保存在服务器,当用户登录校验时候,会从ession中取出对比是否一致 但是前后端分离之后 由于跨域问题 以上就无法实现了 下面这种情况没…

Docker 是什么,Docker 常用命令,怎么写Dockerfile

Docker 是什么 Docker 是一个开源的应用容器引擎&#xff0c;它允许开发者将应用及其依赖打包成一个标准化的单元&#xff0c;这个单元可以在任何支持Docker的环境中运行。 轻量级和可移植性&#xff1a;Docker容器相比于传统的虚拟机更加轻量&#xff0c;因为它们不需要额外…

完整指南:如何使用 Stable Diffusion API

Stable Diffusion 是一个先进的深度学习模型&#xff0c;用于创造和修改图像。这个模型能够基于文本描述来生成图像&#xff0c;让机器理解和实现用户的创意。使用这项技术的关键在于掌握其 API&#xff0c;通过编程来操控图像生成的过程。 在探索 Stable Diffusion API 的世界…

【学习总结】Ubuntu中vscode用ROS插件调试C++程序

1、教程 参考博客&#xff1a; 【ROS】 在VScode中 ROS Debug 配置方法非常详细版 关于launch文件的配置&#xff1a; launch.json {"version": "0.2.0","configurations": [{"name": "ROS: Launch","request"…

Midjourney如何使用“风格参考”和“角色参考”功能

1. 风格参考&#xff08;Style References&#xff09;功能 什么是风格参考&#xff1f; 风格参考功能允许用户引用其他图片的风格&#xff0c;或在多张图片中保持一致的风格。它类似于图片提示&#xff0c;但专注于风格的模仿。 如何使用风格参考&#xff1f; 在提示语之后输入…

word 及PPT 中修改公式字体

主要参考&#xff1a; 1.word修改公式默认字体并打出漂亮公式_word 公式 字体-CSDN博客 2.word 使用数学公式字体 在2中 提供的 链接下载字体&#xff0c;或者可以在这里直接下载&#xff0c;下载链接&#xff1a; https://www.lanzoub.com/iNt3g1rs3w0h 密码:a52p 然后按…

MacOS安装Homebrew教程

Homebrew 是 macOS&#xff08;或 Linux&#xff09;上的一个包管理器&#xff0c;它简化了软件的安装过程。以下是在 macOS 上安装 Homebrew 的步骤&#xff1a; 1. 打开终端 首先&#xff0c;你需要打开 Terminal.app。你可以通过在 Spotlight 搜索中输入“Terminal”或在 …

Linux进程通信补充——System V通信

三、System V进程通信 ​ System V是一个单独设计的内核模块&#xff1b; ​ 这套标准的设计不符合Linux下一切皆文件的思想&#xff0c;尽管隶属于文件部分&#xff0c;但是已经是一个独立的模块&#xff0c;并且shmid与文件描述符之间的兼容性做的并不好&#xff0c;网络通…

【K8S】docker和K8S(kubernetes)理解?docker是什么?K8S架构、Master节点 Node节点 K8S架构图

docker和K8S理解 一、docker的问世虚拟机是什么&#xff1f;Docker的问世&#xff1f;docker优点及理解 二、Kubernetes-K8SK8S是什么&#xff1f;简单了解K8S架构Master节点Node节点K8S架构图 一、docker的问世 在LXC(Linux container)Linux容器虚拟技术出现之前&#xff0c;业…

云手机的数据安全有保障吗?

随着移动互联网的迅速发展&#xff0c;云手机作为一种新兴的移动终端技术&#xff0c;正在逐渐受到人们的关注和应用。然而&#xff0c;对于云手机而言&#xff0c;数据安全问题一直是人们关注的焦点之一。本文将探讨云手机的数据安全性&#xff0c;并分析其是否具备足够的保障…

打造坚不可摧的防线:容灾策略的实践与探索

在当今这个信息化时代&#xff0c;数据已成为企业最宝贵的财富之一。因此&#xff0c;保护数据免受意外损坏或灾难性事件的影响变得至关重要。这就需要企业建立一个有效的容灾体系&#xff0c;来确保业务连续性和数据安全。 容灾&#xff0c;即灾难恢复&#xff08;Disaster Re…

huawei 华为交换机 配置手工模式链路聚合示例

组网需求 如 图 3-21 所示&#xff0c; SwitchA 和 SwitchB 通过以太链路分别都连接 VLAN10 和 VLAN20 的网络&#xff0c;SwitchA 和 SwitchB 之间有较大的数据流量。 用户希望SwitchA 和 SwitchB 之间能够提供较大的链路带宽来使相同 VLAN 间互相通信。 同时用户也希望能够提…

csv编辑器是干什么的?

csv编辑器是一种用于编写、编辑和管理文本文件的工具。适用于 JetBrains IDE 系列的 CSV 编辑器插件&#xff0c;此插件将 CSV&#xff08;逗号分隔值&#xff09;作为一种语言引入 Jetbrains IDE&#xff0c;其中包含语法定义、结构化语言元素和关联的文件类型 &#xff08;.c…

基于Java+SpringBoot+Vue前后端分离婚纱影楼管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行交流合作✌ 主要内容&#xff1a;SpringBoot、Vue、SSM、HLM…

MacBook远程桌面Windows使用Microsoft Remote Desktop for Mac_亲测使用

MacBook远程桌面Windows使用Microsoft Remote Desktop for Mac_亲测使用 像Windows上有自带的远程桌面连接软件.MacBook没有自带的远程连接Windows桌面的工具,需要安装软件来实现. 像远程桌面控制软件一般有 TeamViewer、向日葵远程控制, ToDesk, Microsoft Remote Desktop f…

使用Linux指令将Hex文件与二进制文件的相互转换

文章目录 小结问题及解决参考 小结 本文记录了使用Linux指令将Hex文件与二进制文件的相互转换。 问题及解决 在很多情况下需要将Hex内容的问题转换成二进制文件&#xff0c;另外的情况是&#xff0c;需要将二进制文件转换成Hex内容的文件。例如&#xff1a;需要进行hex字符串…

云计算与大数据课程笔记(六)之Apache Tez/Pig辅助笔记

Apache Tez Apache Tez 是一个为 Hadoop 集群设计的通用数据处理框架&#xff0c;主要用于优化 MapReduce 计算模型的执行效率。Tez 通过允许复杂的数据流图来表示数据处理任务&#xff0c;提高了在 YARN&#xff08;Yet Another Resource Negotiator&#xff09;上执行这些任…

vue实现element-UI中table表格背景颜色设置

目前在style中设置不了&#xff0c;那么就在前面组件给设置上 :header-cell-style"{ color: #ffffff, fontSize: 14px, backgroundColor: #0E2152 }" :cell-style"{ color: #ffffff, fontSize: 14px, backgroundColor: #0E2152 }"

宠物智能喂食机方案设计

我们都知道&#xff0c;现如今养宠物的人群已经很多了&#xff0c;主要是青年人居多&#xff0c;他们在独自漂泊的在外的工作&#xff0c;免不了情感泛滥&#xff0c;养一些小动物也是在预料之中。但由于工作或者其他各种因数&#xff0c;养宠人不可时时刻刻在家&#xff0c;对…