SpringBoot使用自定义注解+AOP+Redis实现接口限流的实例代码
作者:Jae1995 发布时间:2022-04-11 09:15:45
标签:SpringBoot,自定义注解,接口限流
为什么要限流
系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用。为了避免这种情况,我们就需要对接口请求进行限流。
所以,我们可以通过对并发访问请求进行限速或者一个时间窗口内的的请求数量进行限速来保护系统或避免不必要的资源浪费,一旦达到限制速率则可以拒绝服务、排队或等待。
限流背景
系统有一个获取手机短信验证码的接口,因为是开放接口,所以为了避免用户不断的发送请求获取验证码,防止恶意刷接口的情况发生,于是用最简单的计数器方式做了限流,限制每个IP每分钟只能请求一次,然后其他每个手机号的时间窗口限制则是通过业务逻辑进行判断。一般一些接口访问量比较大的,可能会压垮系统的,则需要加入流量限制!如:秒杀等...
实现限流
1、引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、自定义限流注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimiter
{
/**
* 限流key
*/
String key() default Constants.RATE_LIMIT_KEY;
/**
* 限流时间,单位秒
*/
int time() default 60;
/**
* 限流次数
*/
int count() default 100;
/**
* 限流类型
*/
LimitType limitType() default LimitType.DEFAULT;
/**
* 限流后返回的文字
*/
String limitMsg() default "访问过于频繁,请稍候再试";
}
3、限流切面
@Aspect
@Component
public class RateLimiterAspect {
private final static Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
@Autowired
private RedisUtils redisUtils;
@Before("@annotation(rateLimiter)")
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
{
int time = rateLimiter.time();
int count = rateLimiter.count();
long total = 1L;
String combineKey = getCombineKey(rateLimiter, point);
try
{
if(redisUtils.hasKey(combineKey)){
total = redisUtils.incr(combineKey,1); //请求进来,对应的key加1
if(total > count)
throw new ServiceRuntimeException(rateLimiter.limitMsg());
}else{
redisUtils.set(combineKey,1,time); //初始化key
}
}
catch (ServiceRuntimeException e)
{
throw e;
}
catch (Exception e)
{
throw new ServiceRuntimeException("网络繁忙,请稍候再试");
}
}
/**
* 获取限流key
* @param rateLimiter
* @param point
* @return
*/
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
{
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
if (rateLimiter.limitType() == LimitType.IP)
{
stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-");
}
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class<?> targetClass = method.getDeclaringClass();
stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
return stringBuffer.toString();
}
}
4、写一个简单的接口进行测试
@RestController
public class TestController {
@RateLimiter(time = 60, count = 1, limitType = LimitType.IP, limitMsg = "一分钟内只能请求一次,请稍后重试")
@GetMapping("/hello")
public ResultMsg hello() {
return ResultMsg.success("Hello World!");
}
}
5、全局异常拦截
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 业务异常
*/
@ExceptionHandler(ServiceRuntimeException.class)
public ResultMsg handleServiceException(ServiceRuntimeException e, HttpServletRequest request)
{
return ResultMsg.error(e.getMessage());
}
/**
* 系统异常
*/
@ExceptionHandler(Exception.class)
public ResultMsg handleException(Exception e, HttpServletRequest request)
{
return ResultMsg.error("系统异常");
}
}
6、接口测试
1)第一次发送,正常返回结果
2)一分钟内第二次发送,返回错误,限流提示
来源:https://www.cnblogs.com/jae-tech/p/16625091.html


猜你喜欢
- 本文实例讲述了C#实现将浮点数表示的货币数量以汉字大写形式输出的方法。分享给大家供大家参考。具体如下:1.函数代码注:本段代码中能转化的最大
- 为什么需要Spring MVC最开始接触网页的时候,是纯的html/css页面,那个时候还是用Dreamweaver来绘制页面。随着网站开发
- * 可以说是Android开发中最常用的东西之一。我们通过 * 可以监听对象的各种变化事件,并进行一些需要的处理,相当有用,而且使用起来也
- 知识点:1.使用SQL Helper创建数据库2.数据的增删查改(PRDU:Put、Read、Delete、Update)背景知识:上篇文章
- 1.导包(1)c3p0 数据库连接池c3p0配置文件加入到src目录下(2)dbutils:对jdbc操作进行了封装it-cast工具包 包
- 传统“长轮询”实现Web端即时通讯的问题WebSocket出现之前,Web端为了实现即时通讯,所用的技术都是Ajax轮询(polling)。
- 前言基于SpingBoot框架中, 我们随处可以见的便是各种各样的功能注解, 注解的实现原理AOP之前有说过(翻看本系列的前面几章即可),
- 关于人脸识别目前的人脸识别已经相对成熟,有各种收费免费的商业方案和开源方案,其中OpenCV很早就支持了人脸识别,在我选择人脸识别开发库时,
- 一、什么是设计模式设计模式(Design pattern) 是解决软件开发某些特定问题而提出的一些解决方案也可以理解成解决问题的一
- 本文实例讲述了C#同步网络时间的方法。分享给大家供大家参考。具体分析如下:客户的机器的系统时间经常出错,导致给他们做的软件无法正常使用,所以
- 何为高阶函数 大家可能对这个名词并不熟悉,但是这个名词所表达的事物却是我们经常使用到的。只要我们的函
- 前言碎语Disruptor是英国LMAX公司开源的高性能的线程间传递消息的并发框架,和jdk中的BlockingQueue非常类似,但是性能
- 摘要:现在在项目中使用的MybatisPlus,最近研究了一下流程框架Flowable,看了很多技术文档博客,打算直接整合进去,先记录一下遇
- 学习Java实现飞机航班管理系统,本文有该系统的功能截图,和数据库设计SQL语句供大家参考1.飞机航班管理系统背景本系统模拟飞机航班管理业务
- Spring流程Debug1.1 Spring测试环境搭建Spring模块概览,绿色是模块,Spring中八大模块,黑色表示该模块包含的ja
- 有了上一节中得到的正则表达式,那么就可以用来构造 NFA 了。NFA 可以很容易的从正则表达式转换而来,也有助于理解正则表达式表示的模式。一
- Example官方介绍Query by Example (QBE) is a user-friendly querying techniqu
- 本文主要给大家介绍的是关于Android实现微信雷达扫描效果的相关内容,分享出来供大家参考学习,下面来看看详细的介绍:废话不多说 先上图(用
- maven没有打包xml文件的问题最近使用maven带管理项目,采用SSM的技术栈,在配置好一些配置文件,打包部署到tomcat上,出现没有
- 一、创建springboot项目(采用骨架方式)创建完成;我们分析下pom文件中内容:所使用到的关键依赖: <!--springBoo