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

news2024/11/11 5:12:44

目录

前言

思路

实现方式

实践

        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 {
    @Resource
    private 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)拼接key
        String 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 {

    @Bean
    public 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.coloradmin.cn/o/1527757.html

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

相关文章

诺视科技完成亿元Pre-A2轮融资,加速Micro-LED微显示芯片商业化落地

近日&#xff0c;Micro-LED微显示芯片研发商诺视科技&#xff08;苏州&#xff09;有限公司&#xff08;以下简称“诺视科技”&#xff09;宣布完成亿元Pre-A2轮融资&#xff0c;本轮融资由力合资本领投&#xff0c;老股东盛景嘉成、汕韩基金以及九合创投持续加码&#xff0c;这…

YOLOv8改进 | 图像去雾 | MB-TaylorFormer改善YOLOv8高分辨率和图像去雾检测(ICCV,全网独家首发)

一、本文介绍 本文给大家带来的改进机制是图像去雾MB-TaylorFormer,其发布于2023年的国际计算机视觉会议(ICCV)上,可以算是一遍比较权威的图像去雾网络, MB-TaylorFormer是一种为图像去雾设计的多分支高效Transformer网络,它通过应用泰勒公式展开的方式来近似softmax-at…

华为openEuler系统安装openjdk并配置环境变量

华为openEuler系统安装openjdk并配置环境变量 1、安装JDK软件包 执行dnf list installed | grep jdk 查询JDK软件是否已安装。 $ dnf list installed | grep jdk查看命令打印信息&#xff0c;若打印信息中包含“jdk”&#xff0c;表示该软件已经安装了&#xff0c;则不需要再…

堆排序(向下调整法,向上调整法详解)

目录 一、 二叉树的顺序结构 二、 堆的概念及结构 三、数组存储、顺序存储的规律 此处可能会有疑问&#xff0c;左右孩子的父节点计算为什么可以归纳为一个结论了&#xff1f; 四、大小堆解释 五、大小堆的实现&#xff08;向上和向下调整法&#xff09; 5.11向上调整法…

docxTemplater——从word模板生成docx文件

官网文档&#xff1a;Get Started (Browser) | docxtemplater 官网在线演示&#xff1a;Demo of Docxtemplater with all modules active | docxtemplater 源码&#xff1a;https://github.com/open-xml-templating/docxtemplater 不仅可以处理word&#xff08;免费&#xf…

【深度学习实践】面部表情识别,深度学习分类模型,mmpretrain用于分类的实用教程,多任务网络头

文章目录 数据集数据集的进一步处理转换training.csv转换validation.csv 剔除无法使用的图片数据选择mmpretrain框架来训练配置四个文件改写base model改写base datasetsschedulesdefault_runtime 总配置开始训练训练分析考虑在网络上增加facial_landmarks回归head考虑是否可以…

论文解析:V3D: Video Diffusion Models are Effective 3DGenerators

摘要&#xff1a; 自动三维生成最近引起了广泛关注。最近的方法大大加快了生成速度&#xff0c;但由于模型容量有限或三维数据&#xff0c;生成的物体通常不够精细。在视频扩散模型最新进展的推动下&#xff0c;我们引入了 V3D&#xff0c;利用预训练视频扩散模型的世界模拟能…

【已解决】MySQL:常用的除法运算+精度处理+除数为0处理

目录 问题现象&#xff1a; 问题分析&#xff1a; 拓展&#xff1a; 1、除法运算&#xff1a; 拓展&#xff1a;MySQL中常用的几种除法运算 1、取整除法 2、浮点数除法 3、取余除法 4、向上取整除法 5、向下取整除法 2、运算结果的精度处理 1.1、浮点数 1.2、总位数 1.3、…

蓝桥杯练习题——健身大调查

在浏览器中预览 index.html 页面效果如下&#xff1a; 目标 完成 js/index.js 中的 formSubmit 函数&#xff0c;用户填写表单信息后&#xff0c;点击蓝色提交按钮&#xff0c;表单项隐藏&#xff0c;页面显示用户提交的表单信息&#xff08;在 id 为 result 的元素显示&#…

2024年敏捷产品负责人CSPO认证培训

课程名称&#xff1a;Scrum Product Owner CSPO产品负责人认证 课程类型&#xff1a;经理级 课程简介&#xff1a; Scrum Product Owner产品负责人在Scrum产品开发当中扮演“舵手”的角色&#xff0c;他决定产品的愿景、路线图以及投资回报&#xff0c;他需要回答为什么做&am…

【ZooKeeper】2、安装

本文基于 Apache ZooKeeper Release 3.7.0 版本书写 作于 2022年3月6日 14:22:11 转载请声明 下载zookeeper安装包 wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz解压 tar -zxvf apache-zookeeper-3.7.0-b…

OpenCV Steger算法提取条纹中心线

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 Steger 算法是一种常用的图像边缘检测算法,可以用于提取图像中的中心线或边缘信息。它的理论假设是:条纹的亮度是按照高斯分布呈现的,即中心亮两侧渐暗。 其计算过程如下所述: 1、首先,我们需要计算每个点Hess…

汽车制造业供应商管理会面临哪些问题?要如何解决?

汽车行业的供应链是及其复杂的&#xff0c;并且呈全球化分布&#xff0c;企业在知识产权方面的优势很可能是阶段性的。企业需要持续保持领先&#xff0c;将面临巨大的挑战&#xff0c;尽快地将产品推向市场是保持领先的唯一途径。然而&#xff0c;如果没有正确的方式去实现安全…

Flutter 运行 flutter doctor 命令长时间未响应

由于 Flutter 运行 flutter doctor 命令&#xff0c;会从 pub(https://pub.dev/ 类似于 Node.js 的 npm) 上进行资源的下载&#xff0c;如果没有配置国内镜像&#xff0c;可能会由于其服务器在国外导致资源下载慢或者下载不下来&#xff0c;所以出现了运行 flutter doctor 命令…

中国银行信息系统应用架构发展历程

概述&#xff1a; 从 20 世纪 80 年代开始至今&#xff0c;我国银行业信息化历程已 有四十年历史。虽然相对于发达国家来讲&#xff0c;我国银行业务信 息化起步较晚&#xff0c;但发展速度很快&#xff0c; 目前我国一些大型商业银行的信息化程度已经处于全球领先水平。 “银行…

【IC设计】Verilog线性序列机点灯案例(四)(小梅哥课程)

文章目录 该系列目录&#xff1a;设计环境设计目标设计思路RTL及Testbench代码RTL代码Testbenchxdc约束 仿真结果 声明&#xff1a;案例和代码来自小梅哥课程&#xff0c;本人仅对知识点做做笔记&#xff0c;如有学习需要请支持官方正版。 该系列目录&#xff1a; Verilog线性…

使用Composer安装Laravel框架

使用Composer安装Laravel框架&#xff0c;不指定版本则安装当下最新版本 composer create-project laravel/laravel laravel-demo 至此&#xff0c;安装框架完成&#xff0c;这里安装的是Laravel11.0.7版本的 进入项目根目录&#xff0c;运行项目 cd laravel.11.0.7 // 进…

maven一点通

1.maven简介 Maven是一个基于Java的工程构建工具&#xff0c;用于管理和构建项目的依赖关系。它提供了一种标准的项目结构和一组约定&#xff0c;使得项目的开发、构建、部署和文档化更加容易和可靠。 Maven的主要功能包括&#xff1a; 依赖管理&#xff1a;Maven可以自动下载…

最细致最简单的 Arm 架构搭建 Harbor

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; ARM离线版本安装 官方提供了一个 arm 版本&#xff0c;但是好久都没更新了&#xff0c;地址&#xff1a;https://github.com/goharbor/harbor-arm 。 也不知道为什么不更新&#xff0c;我看…

Cookie 信息泄露 Cookie未设置http only属性 原理以及修复方法

漏洞名称&#xff1a;Cookie信息泄露、Cookie安全性漏洞、Cookie未设置httponly属性 漏洞描述&#xff1a; cookie的属性设置不当可能会造成系统用户安全隐患&#xff0c;Cookie信息泄露是Cookiehttp only配置缺陷引起的&#xff0c;在设置Cookie时&#xff0c;可以设置的一个…