SpringBoot 自定义注解实现限流

限流是为了防止服务器资源的过度消耗,通过一定的策略来控制访问频率,确保服务的高可用性和稳定性。其核心意义在于防止流量高峰时期接口过载,从而引起服务崩溃或响应延迟增加。本文将简述如何通过AOP和自定义注解实现限流。
1.创建自定义注解
可以根据需要定义更多方法,在方法上引用注解需要指定具体的值

@Target(ElementType.METHOD)  //注解的目标是方法上
@Retention(RetentionPolicy.RUNTIME) //运行时
@Documented
public @interface RateLimit {String key() default "";int time() default 1; //时间,单位秒,默认1秒int count() default 100; // 允许的请求次数 ,此处为1秒100次
}

2.定义限流切面
使用AOP切面来控制方法的请求次数,如超过注解定义的请求次数限制,将抛出异常


import com.google.common.util.concurrent.RateLimiter;import com.lenovo.ssc.logistics.system.RateLimit;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Component
@Aspect
public class RateLimitAspect {private final Map<String ,RateLimiter> limiterMap=new ConcurrentHashMap<>();@Before("@annotation(rateLimit)")public void doBefore(JoinPoint point, RateLimit rateLimit){MethodSignature signature= (MethodSignature)point.getSignature();//获取方法签名Method method = signature.getMethod();//获取当前方法String name = method.getName();//获取方法名double permitsSecond=(double)rateLimit.count()/ rateLimit.time();//计算每秒允许的请求数//computeIfAbsent 方法会检查 limiterMap 中是否存在键 name。如果键 name 不存在,则使用提供的 lambda 表达式 k -> RateLimiter.create(rateLimit.count()) 创建一个新的值,并将其与键 name 关联com.google.common.util.concurrent.RateLimiter rateLimiter = limiterMap.computeIfAbsent(name, k ->  com.google.common.util.concurrent.RateLimiter.create(permitsSecond));if(!rateLimiter.tryAcquire()){//ateLimiter.tryAcquire() 方法用于尝试从 Guava 的 RateLimiter 限流器中获取一个许可(token)。如果能够成功获取许可,则返回 true,否则返回 falsethrow new RuntimeException("Too many requests");}}}

3.使用注解
在Controller中使用@RateLimit注解,time用于指定时间内,count为请求次数

    @GetMapping("/queryUsageMap")@Operation(summary = "获取用途map")@RateLimit(key="queryUsageMap",time = 60,count = 10)public Message<List<Map<String, String>>> queryUsageMap(@RequestParam String language) {List<Map<String, String>> usageList = SealUsageEnum.getUsageList();if (!StringUtils.isEmpty(language)) {if ("en-US".equals(language)) {usageList = SealUsageEnum.getUsageListInEg();}}return new Message<>(ResultCodeEnum.SUCCESS.getCode().toString(), ResultCodeEnum.SUCCESS.getMessage(), usageList);}

4.测试效果
在方法上增加注解,规定时间内,正常访问;超出频率报错如下:

java.lang.RuntimeException: Too many requestsat com.lenovo.ssc.logistics.system.aspect.RateLimitAspect.doBefore(RateLimitAspect.java:36)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.base/java.lang.reflect.Method.invoke(Method.java:568)at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:617)at org.springframework.aop.aspectj.AspectJMethodBeforeAdvice.before(AspectJMethodBeforeAdvice.java:44)at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:57)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762)at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:707)at com.lenovo.ssc.logistics.seal.controller.SealBasicController$$EnhancerBySpringCGLIB$$cfa31bbb.queryUsageMap(<generated>)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.base/java.lang.reflect.Method.invoke(Method.java:568)at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072)at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)at javax.servlet.http.HttpServlet.service(HttpServlet.java:529)at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)

注意:未使用该注解的方法,将不受限制
以上是使用自定义注解和AOP完成限流的所有内容,更多的限流方式如Bucket4j、Spring Cloud gateway 以及限流组件Sentinel等,关注博主后续。如有不当之处,可以在评论区评论。

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

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

相关文章

Unity——QFramework框架 内置工具

QFramework 除了提供了一套架构之外&#xff0c;QFramework 还提供了可以脱离架构使用的工具 TypeEventSystem、EasyEvent、BindableProperty、IOCContainer。 这些工具并不是有意提供&#xff0c;而是 QFramework 的架构在设计之初是通过这几个工具组合使用而成的。 内置工具…

Vue3.5 企业级管理系统实战(二十二):动态菜单

在前几篇内容中已完成菜单、角色及菜单权限等相关开发&#xff0c;若要在左侧菜单根据用户角色动态展示菜单&#xff0c;需对 Sidebar 中的相关数据进行修改。鉴于其他相关方法及类型已在前文实现&#xff0c;本文不再重复阐述。 1 修改 Sidebar 组件 在 src/layout/componen…

014校园管理系统技术解析:构建智慧校园管理平台

校园管理系统技术解析&#xff1a;构建智慧校园管理平台 在教育信息化快速发展的当下&#xff0c;校园管理系统成为提升学校管理效率、优化校园服务的重要工具。该系统集成院校管理、投票管理等多个核心模块&#xff0c;面向管理员、用户和院内管理员三种角色&#xff0c;通过…

创新农业社会化服务 中和农信服务小农户的探索实践

在实现乡村振兴的道路上&#xff0c;如何让现代农业发展成果惠及广大小农户&#xff0c;是一个重要课题。作为国内领先的综合助农机构&#xff0c;中和农信多年来深耕农村市场&#xff0c;在服务小农户方面进行了诸多创新探索&#xff0c;走出了一条具有示范意义的农业社会化服…

6.3 day 35

知识点回顾&#xff1a; 三种不同的模型可视化方法&#xff1a;推荐torchinfo打印summary权重分布可视化进度条功能&#xff1a;手动和自动写法&#xff0c;让打印结果更加美观推理的写法&#xff1a;评估模式 可视化 理解深度学习网络最重要的2点&#xff1a; 1.了解损失如何定…

【如何在IntelliJ IDEA中新建Spring Boot项目(基于JDK 21 + Maven)】

AA. 我的开发环境配置与核心工具链解析 一、开发环境全览 C:\Users\Again>java -version java version "21.0.1" 2023-10-17 LTS Java(TM) SE Runtime Environment (build 21.0.112-LTS-29) Java HotSpot(TM) 64-Bit Server VM (build 21.0.112-LTS-29, mixed m…

【C++高级主题】多重继承下的类作用域

目录 一、类作用域与名字查找规则&#xff1a;理解二义性的根源 1.1 类作用域的基本概念 1.2 单继承的名字查找流程 1.3 多重继承的名字查找特殊性 1.4 关键规则&#xff1a;“最近” 作用域优先&#xff0c;但多重继承无 “最近” 二、多重继承二义性的典型类型与代码示…

登录vmware vcenter报vSphere Client service has stopped working错误

一、问题 登录vmware vcenter时发现报vSphere Client service has stopped working错误&#xff0c;导致vcenter控制台进不去 二、解决办法 打开vmware vcenter管理https://vcenterIP:5480&#xff0c;选择VMware vSphere Client&#xff0c;重启该服务后恢复正常。

MySQL关系型数据库学习

学习参考链接&#xff1a;https://www.runoob.com/mysql/mysql-tutorial.html Windows 安装MYSQL服务端的步骤&#xff1a;https://www.runoob.com/w3cnote/windows10-mysql-installer.html 1. 概念学习 MySQL 是一种关联数据库管理系统&#xff0c;关联数据库将数据保存在不…

web攻防之SSTI 注入漏洞

知识简介 &#xff1a; 模版引擎和框架的区别 ssti的中文翻译 &#xff1a; 服务端的模版的注入 模版引擎 &#xff1a;前端的用于装饰优化html的模版 最简单的就是在腾讯会议中的聊天功能 框架 &#xff1a; 这个是一套独立存在的逻辑 如TP他是一个区别于php语法的后端逻辑…

【清晰教程】利用Git工具将本地项目push上传至GitHub仓库中

Git 是一个分布式版本控制系统&#xff0c;由 Linus Torvalds 创建&#xff0c;用于有效、高速地处理从小到大的项目版本管理。GitHub 是一个基于 Git 的代码托管平台&#xff0c;提供了额外的协作和社交功能&#xff0c;使项目管理更加高效。它们为项目代码管理、团队协作和持…

极简以太彩光网络解决方案4.0正式发布,“彩光”重构园区网络极简之道

5月28日下午,锐捷网络在京举办以“光,本该如此‘简单’”为主题的发布会,正式发布极简以太彩光网络解决方案4.0。作为“彩光”方案的全新进化版本,极简以太彩光4.0从用户需求出发,聚焦场景洞察,开启了一场从底层基因出发的极简革命,通过架构、部署、运维等多维度的创新升级,以强…

Selenium 中 JavaScript 点击的优势及使用场景

*在 Selenium 自动化测试中&#xff0c;使用 JavaScript 执行点击操作&#xff08;如driver.execute_script("arguments[0].click();", element)&#xff09;相比直接调用element.click()有以下几个主要优势&#xff1a; 1. 绕过元素不可点击的限制 问题场景&#x…

CppCon 2014 学习:Cross platform GUID association with types

类型的 GUID&#xff08;全局唯一标识符&#xff09; 是在 COM 编程&#xff08;Component Object Model&#xff09; 和某些大型 C 架构&#xff08;如 Office、DirectX、跨 DLL 接口&#xff09;中关联类型信息和实现运行时类型识别与动态接口查询的重要机制。 下面我们分层解…

Android 11以上App主动连接WIFI的完整方案

早期Android版本App内连接指定的WIFI还是比较简单的&#xff0c;但是随着Android版本的提升&#xff0c;限制也越来越多。以下是一套完整的Android 11以上的WIFI应用内主动连接方案。 第一步&#xff1a;添加到建议连接&#xff1a; val wifiManager getSystemService(WIFI_…

让AI弹琴作曲不再是梦:Python+深度学习玩转自动化音乐创作

让AI弹琴作曲不再是梦:Python+深度学习玩转自动化音乐创作 一、AI也能谱出动人的旋律?真不是科幻! 还记得小时候学钢琴时老师的那句经典:“感觉不到情绪的乐句,是没灵魂的。” 当时我一边练琴一边想:要是有个机器能帮我写谱、调性又不跑调就好了! 结果几年后,真被我碰…

机器学习:集成学习概念、分类、随机森林

本文目录&#xff1a; 一、集成学习概念**核心思想&#xff1a;** 二、集成学习分类&#xff08;一&#xff09;Bagging集成&#xff08;二&#xff09;Boosting集成(三&#xff09;两种集成方法对比 三、随机森林 一、集成学习概念 集成学习是一种通过结合多个基学习器&#…

YOLO机械臂丨使用unity搭建仿真环境,YOLO算法识别,Moveit2控制

文章目录 前言搭建开发环境在window中安装Unity创建Docker容器&#xff0c;并安装相关软件运行测试改进添加删除节点前的函数调用 报错❌框选节点的时候报错❌如果无法控制机械臂&#xff0c;查看rviz2的终端&#xff0c;应该会有❌规划路径超出范围 参考 前言 本项目介绍通过…

Docker 插件生态:从网络插件到存储插件的扩展能力解析

Docker 容器技术以其轻量、快速、可移植的特性,迅速成为构建和部署现代应用的核心工具。然而,尽管 Docker Engine 自身功能强大,但在面对多样化的生产环境和复杂业务需求时,仅靠核心功能往往无法满足所有场景。 例如,跨主机的容器网络通信、异构存储系统的持久化数据管理…

飞牛fnNAS使用群辉DSM系统

目录 一、Virtual DSM简介 二、在飞牛NAS中安装 1、激活Docker 2、建立路径 3、创建Compose项目 4、容器启动 (1)构建容器 (2)容器启动 5、查看日志 6、登录DSM地址 7、安装完成 8、安装套件示例 9、远程访问 10、测试 (1)PC浏览器创建笔记 (2)手机创建…