Spring Boot 中使用 Redis + Aop 进行限流

Spring Boot 中使用 Redis 进行限流,通常你可以采用如下几种方式:

  1. 令牌桶算法(Token Bucket)
  2. 漏桶算法(Leaky Bucket)
  3. 固定窗口计数器(Fixed Window Counter)
  4. 滑动日志窗口(Sliding Log Window)

实现 Redis 限流,可以采用 Redis 提供的数据结构和功能脚本,如 Lua 脚本、Redisson 库等。以下是使用 Redis 和 Lua 脚本来实现令牌桶限流算法的示例:

步骤一:编写 Lua 脚本。

下面是一个限流的 Lua 脚本示例,实现基本的限流功能,放在Spring Boot项目下的resources目录下。

--获取KEY
local key = KEYS[1] -- 限流的 keylocal limit = tonumber(ARGV[1]) --注解标注的限流次数local curentLimit = tonumber(redis.call('get', key) or "0")if curentLimit + 1 > limit
then return 0
else-- 自增长 1redis.call('INCRBY', key, 1)-- 设置过期时间redis.call('EXPIRE', key, ARGV[2])return curentLimit + 1
end

步骤二:定义限流注解

package your.package;import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface RedisLimit {/*** 资源的key,唯一* 作用:不同的接口,不同的流量控制*/String key() default "";/*** 最多的访问限制次数*/long permitsPerSecond() default 2;/*** 过期时间也可以理解为单位时间,单位秒,默认60*/long expire() default 60;/*** 得不到令牌的提示语*/String msg() default "系统繁忙,请稍后再试.";
}

步骤三:定义Aop切面类

package your.package;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;/*** Limit AOP*/
@Slf4j
@Aspect
@Component
public class RedisLimitAop {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Pointcut("@annotation(your.package.RedisLimit)")private void check() {}private DefaultRedisScript<Long> redisScript;@PostConstructpublic void init() {redisScript = new DefaultRedisScript<>();redisScript.setResultType(Long.class);redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("rateLimiter.lua")));}@Before("check()")public void before(JoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();//拿到RedisLimit注解,如果存在则说明需要限流RedisLimit redisLimit = method.getAnnotation(RedisLimit.class);if (redisLimit != null) {//获取redis的keyString key = redisLimit.key();String className = method.getDeclaringClass().getName();String name = method.getName();String limitKey = key + className + method.getName();log.info(limitKey);if (StringUtils.isEmpty(key)) {throw new RedisLimitException("key cannot be null");}long limit = redisLimit.permitsPerSecond();long expire = redisLimit.expire();List<String> keys = new ArrayList<>();keys.add(key);Long count = stringRedisTemplate.execute(redisScript, keys, String.valueOf(limit), String.valueOf(expire));log.info("Access try count is {} for key={}", count, key);if (count != null && count == 0) {log.debug("获取key失败,key为{}", key);throw new RedisLimitException(redisLimit.msg());}}}}

步骤四:自定义Redis限流异常

package your.package;/*** Redis限流自定义异常* @date 2023/3/10 21:43*/
public class RedisLimitException extends RuntimeException{public RedisLimitException(String msg) {super( msg );}
}

步骤五:自定义ResultInfo返回实体

package your.package;import lombok.Getter;
import lombok.Setter;@Getter
@Setter
public class ResultInfo<T> {private String message;private String code;private T data;public ResultInfo(String message, String code, T data) {this.message = message;this.code = code;this.data = data;}public static ResultInfo error(String message) {return new ResultInfo(message,"502",null);}}

步骤六:定义Controller接口

package your.package;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@Slf4j
@RestController
@RequestMapping("/limit/redis")
public class LimitRedisController {/*** 基于Redis AOP限流*/@GetMapping("/test")@RedisLimit(key = "redis-limit:test", permitsPerSecond = 2, expire = 1, msg = "当前排队人数较多,请稍后再试!")public String test() {log.info("限流成功。。。");return "ok";}}

效果测试

在这里插入图片描述

实现了上面的步骤之后,Spring Boot应用就可以通过AOP与Redis来进行API限流了。

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

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

相关文章

Java:继承

目录 1.继承1.1为什么要使用继承&#xff1f;1.2继承的概念1.3对继承的理解1.4子类怎么访问父类的成员变量1.4.1不同名怎么访问&#xff1f;1.4.2同名怎么访问&#xff1f;(关键字&#xff1a;super) 1.5子类中访问父类的成员方法1.5.1不同名怎么访问&#xff1f;1.5.2同名怎么…

Apache DolphinScheduler-3.2.0集群部署教程

集群部署方案(2 Master 3 Worker) Apache DolphinScheduler官网&#xff1a;https://dolphinscheduler.apache.org/zh-cnApache DolphinScheduler使用文档&#xff1a;https://dolphinscheduler.apache.org/zh-cn/docs/3.2.0截止2024-01-19&#xff0c;最新版本&#xff1a;3…

Linux - 安装 Jenkins(详细教程)

目录 前言一、简介二、安装前准备三、下载与安装四、配置镜像地址五、启动与关闭六、常用插件的安装 前言 虽然说网上有很多关于 Jenkins 安装的教程&#xff0c;但是大部分都不够详细&#xff0c;或者是需要搭配 docker 或者 k8s 等进行安装&#xff0c;对于新手小白而已&…

BUGKU-WEB shell

题目描述 题目截图如下&#xff1a; 描述&#xff1a; $poc "a#s#s#e#r#t";$poc_1 explode("#", $poc);$poc_2 $poc_1[0].$poc_1[1].$poc_1[2].$poc_1[3].$poc_1[4].$poc_1[5];$poc_2($_GET[s])进入场景看看&#xff1a;是一个空白的界面 解题思路 …

NCP1380BDR2G芯片中文资料规格书PDF数据手册引脚图图片参数功能价格

产品描述&#xff1a; NCP1380 是一款高性能器件&#xff0c;旨在为准谐振转换器供电。该控制器基于专属的谷锁闭系统&#xff0c;可以在功率负载变轻时进行切换并降低开关频率。这样将产生稳定的运行&#xff0c;即使在漏极-源极谷中总是触发的开关事件下也是如此。此系统可在…

让数据在业务间高效流转,镜舟科技与NineData完成产品兼容互认

近日&#xff0c;镜舟科技与NineData完成产品兼容测试。在经过联合测试后&#xff0c;镜舟科技旗下产品与NineData云原生智能数据管理平台完全兼容&#xff0c;整体运行高效稳定。 镜舟科技致力于帮助中国企业构建卓越的数据分析系统&#xff0c;打造独具竞争力的“数据护城河”…

探索 Spring 框架:企业级应用开发的强大工具

CSDN-个人主页&#xff1a;17_Kevin-CSDN博客 收录专栏&#xff1a;《Java》 目录 一、引言 二、Spring 框架的历史 三、Spring 框架的核心模块 四、Spring 框架的优势 五、Spring 框架的应用场景 六、结论 一、引言 在当今数字化时代&#xff0c;企业级应用开发的需求日…

代码随想录刷题笔记 Day 51 | 单词拆分 No.139 | 多重背包理论基础

文章目录 Day 5101. 单词拆分&#xff08;No. 139&#xff09;<1> 题目<2> 笔记<3> 代码 02. 多重背包理论基础2.1 解题思路2.2 携带矿石资源&#xff08;卡码网No.56&#xff09;<1> 题目<2> 笔记<3> 代码 Day 51 01. 单词拆分&#xff…

python-0002-linux安装pycharm

下载软件包 下载地址&#xff1a;https://download.csdn.net/download/qq_41833259/88944791 安装 # 解压 tar -zxvf 你的软件包 # 进入软件解压后的路径&#xff0c;如解压到了/home/soft/pycharm cd /home/soft/pycharm cd bin # 执行启动命令 sh pycharm.sh # 等待软件启…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的手写数字和符号识别(深度学习训练+UI界面+训练数据集)

摘要&#xff1a;开发手写数字和符号识别对于智能交互系统具有关键作用。本篇博客详细介绍了如何运用深度学习构建一个手写数字和符号识别&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并对比了YOLOv7、YOLOv6、YOLOv5&#xff0c;展示了不同模…

STM32F103 CubeMX 定时器输出PWM控制呼吸灯

STM32F103 CubeMX 定时器输出PWM控制呼吸灯 1. 生成代码1. 1 配置外部时钟&#xff0c;SWD口1.2 配置定时器31.3 配置定时器2 2. 代码编写的部分 使用的cubmx 软件的版本&#xff1a;6.2.0 最新版本 6.10&#xff08;2024年3月11日&#xff09; 1. 生成代码 1. 1 配置外部时钟…

C++ 拷贝构造函数和运算符重载

目录 一. 拷贝构造函数 1. 引入 2. 拷贝构造的概念 3. 浅拷贝 4. 深拷贝 二. C运算符重载 1. 概念 2. 注意事项 3.举例 一. 拷贝构造函数 1. 引入 我们在创建对象时&#xff0c;能不能创建一个与原先对象一模一样的新对象呢&#xff1f;为了解决这个问题&#x…

关于PolarDB粗浅认识

PolarDB简介 目前&#xff08;20240314&#xff09;&#xff0c;PolarDB有两个版本&#xff1a; PolarDB-PG PolarDB PostgreSQL 版&#xff08;PolarDB for PostgreSQL&#xff0c;简称“PolarDB-PG”&#xff09;是阿里云自主研发的云原生关系型数据库产品&#xff0c;100%…

主板维修一般多少钱?电脑主板常见维修方法交换法

修主板一般要多少钱&#xff1f; 下面就让我们一起来了解一下吧。 电脑主板维修价格根据损坏程度不同而不同 1、电容器最容易损坏。 如果只是更换电容的话&#xff0c;大约需要50元左右。 2、如果主板上的电路损坏&#xff0c;面积越大&#xff0c;价格就越贵&#xff0c;可…

一学就会 | ChatGPT提示词-[简历指令库]-有爱AI实战教程(七)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 一、导读&#xff1a; 在使用 ChatGPT 时&#xff0c;当你给的指令越精确&#xff0c;它的回答会越到位&#xff0c;举例来说&#xff0c;假如你要请它帮忙写文案&#x…

测算土地面积并导出的新方法

让每一个人&#xff0c;都有自己的地图&#xff01; 我们在《如何测量显示多个距离和面积》一文中分享过测量距离和面积的方法&#xff0c;随着最近新版本的上线&#xff0c;该功能又有了新方法。 这里以测算土地面积并导出为例&#xff0c;分享这个新版本中的面积测量与导出…

某年某月第几天(模拟)

时间模板传送带-> 题目描述 定义一个结构体变量&#xff08;包括年、月、日&#xff09;。计算该日在本年中是第几天&#xff0c;注意闰年问题。 输入格式 年月日 输出格式 当年第几天 样例输入 2000 12 31 样例输出 366 #include <iostream> using namespace s…

黑天鹅大事件发生后,财产如何不受损失,fpmarkets一招教你

众所周知一旦行业内发生黑天鹅后&#xff0c;所带来的影响可以颠覆整个行业&#xff0c;再加上爆发的瞬间性对我们危害更大。那么黑天鹅大事件发生后&#xff0c;财产如何不受损失&#xff0c;今天fpmarkets一招教你。 塔勒布在《黑天鹅:极不可能事件的影响》一书中写道&#x…

一条 SQL 更新语句如何执行的

Server 层 存储引擎层 总流程 查询语句 连接器 查询缓存 分析器 优化器 执行器 更新语句 redo log&#xff08;节省的是随机写磁盘的 IO 消耗&#xff08;转成顺序写&#x…

骨传导耳机领头羊——南卡在AWE2024展会上展现强大的创新实力

在2024年的AWE&#xff08;中国家电及消费电子博览会&#xff09;上&#xff0c;南卡凭借其尖端的骨传导耳机技术再次成为业界瞩目的中心。作为骨传导技术的先驱和领航者&#xff0c;南卡不仅展出了其最新的产品&#xff0c;更向世界宣布了其在开放式耳机市场的宏伟蓝图。 南卡…