springboot+RateLimiter+AOP自定义注解限流

springboot+RateLimiter+AOP自定义注解限流

  • RateLimiter简介
  • springboot集成RateLimiter
    • pom.xml引入
    • RateLimiter常用api
    • 代码实现
      • 自定义注解Limiter
      • 限流切面
      • 验证

RateLimiter简介

RateLimiter是Guava库中的一个限流器,它提供如下功能:
(1)基于PPS进行限流
(2)基于PPS限流的同时提供热启动

springboot集成RateLimiter

pom.xml引入

<!--引入guava依赖-->
<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>31.1-jre</version>
</dependency>

RateLimiter常用api

(1)RateLimiter.create(double permitsPerSecond); ===> 指定速率,每秒产生permitsPerSecond个令牌
(2)rateLimiter.acquire(int permits); ===> 返回获取permits个令牌所需的时间
(3)rateLimiter.tryAcquire(1); ===> 获取1个令牌,返回false获取失败,true获取成功
(4)rateLimiter.tryAcquire(1, 2, TimeUnit.SECONDS); ===> 获取1个令牌,最多等待两秒。返回false获取失败,true获取成功

package com.mry.springboottools.controller;

import com.google.common.util.concurrent.RateLimiter;

import java.util.concurrent.TimeUnit;

/**
 * RateLimiter测试类
 */
public class RateLimiterTest {

    public static void main(String[] args) {
        //指定速率,每秒产生一个令牌  
        RateLimiter rateLimiter = RateLimiter.create(1);
        System.out.println(rateLimiter.getRate());
        //修改为每秒产生2个令牌
        rateLimiter.setRate(2);
        System.out.println(rateLimiter.getRate());

        //while (true) {  
        //获取2个令牌所需要的时间  
        double acquire = rateLimiter.acquire(2);
        //输出结果, 第一次0秒,后面每次等待接近0.5秒的时间  
        //0.0  
        //0.995198  
        //0.9897  
        //0.999413  
        //0.998272  
        //0.99202  
        //0.993757  
        //0.996198  
        //0.99523  
        //0.99532  
        //0.992674  
        System.out.println(acquire);
        // }  
        //获取1个令牌  
        boolean result = rateLimiter.tryAcquire(1);
        System.out.println(result);
        //获取1个令牌,最多等待两秒  
        boolean result2 = rateLimiter.tryAcquire(1, 2, TimeUnit.SECONDS);
        System.out.println(result2);

    }
}


代码实现

自定义注解Limiter

package com.mry.springboottools.annotation;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * 限流注解
 *
 * @author
 * @date
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Limiter {

    /**
     * 不进行限流
     */
    int NOT_LIMITED = 0;

    /**
     * qps (每秒并发量)
     */
    double qps() default NOT_LIMITED;

    /**
     * 超时时长,默认不等待
     */
    int timeout() default 0;

    /**
     * 超时时间单位,默认毫秒
     */
    TimeUnit timeUnit() default TimeUnit.MILLISECONDS;

    /**
     * 返回错误信息
     */
    String msg() default "系统忙,请稍后再试";

}


限流切面

package com.mry.springboottools.aspect;

import com.google.common.util.concurrent.RateLimiter;
import com.mry.springboottools.annotation.Limiter;
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.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 限流切面
 * @author
 * @date
 */
@Slf4j
@Aspect
@Component
public class RateLimiterAspect {
    /**
     * key: 类全路径+方法名
     */
    private static final ConcurrentMap<String, RateLimiter> RATE_LIMITER_CACHE = new ConcurrentHashMap<>();


    @Around("@within(limiter) || @annotation(limiter)")
    public Object pointcut(ProceedingJoinPoint point, Limiter limiter) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        if (limiter != null && limiter.qps() > Limiter.NOT_LIMITED) {
            double qps = limiter.qps();
            //这个key可以根据具体需求配置,例如根据ip限制,或用户
            String key = method.getDeclaringClass().getName() + method.getName();
            if (RATE_LIMITER_CACHE.get(key) == null) {
                // 初始化 QPS
                RATE_LIMITER_CACHE.put(key, RateLimiter.create(qps));
            }
            // 尝试获取令牌
            if (RATE_LIMITER_CACHE.get(key) != null && !RATE_LIMITER_CACHE.get(key).tryAcquire(limiter.timeout(), limiter.timeUnit())) {
                log.error("触发限流操作{}", key);
                throw new RuntimeException(limiter.msg());
            }
        }
        return point.proceed();
    }

}

验证

package com.mry.springboottools.controller;

import com.google.common.util.concurrent.RateLimiter;
import com.mry.springboottools.annotation.Limiter;
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;
import java.util.concurrent.TimeUnit;

/**
 * 测试限流
 * @author
 * @date
 */
@RestController
@RequestMapping("limiter")
@Slf4j
public class RateLimiterController {

    @GetMapping
    @Limiter(qps = 1, msg = "您已被限流!")
    public String getUserName() {
        String userName = "mry";
        log.info("userName = {}", userName);
        return userName;
    }
}

接口请求:
在这里插入图片描述

日志输出:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ext-1:PDK工具包编译出例程

1、TI的单独StarterWare不更新后&#xff0c;后续维护和更新的是 PROCESSOR-SDK-AM335X 软件开发套件 &#xff08;PDK&#xff09;&#xff0c;对比以前的&#xff0c;里面没有例程&#xff0c;所以下载安装完需要自己编译出example例程。 因为编译出example例程中间会出现很…

深元边缘计算盒子在社区的应用,提高社区的安全性和生活质量

近年来&#xff0c;随着人工智能技术的不断发展和普及&#xff0c;越来越多的社区开始应用边缘计算盒子AI视觉分析技术&#xff0c;以提高社区的安全性和管理效率。本文将介绍边缘计算盒子AI视觉分析技术在社区中的应用及其优势。 一、边缘计算盒子AI视觉在社区中的应用 1.安防…

C++类的模拟实现

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容讲解了简单模拟实现string类 C类的模拟实现 文章目录 C类的…

centos7部署FastDFS服务

一、安装需要的相关依赖 yum -y install make cmake gcc gcc-c 因为我的服务器已经安装了gcc&#xff0c;所以略去 使用gcc -v查看版本 yum -y install zip unzip 安装性能事件通知库 yum -y install libevent 安装nginx依赖 yum -y install libevent yum -y install zli…

OSCP-Fail(rsync、fail2ban提权)

目录 扫描 rsync 提权 扫描 rsync 基于nmap,确信将进一步研究rsync。 为此,将使用netcat使用的rsync枚举。 使用netcat,我们可以列出rsync托管的当前共享。 我们看到“fox”和“fox home

大数据管理中心规划设计方案(ppt可编辑)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除。 统一汇聚 推动业务数据协同5 价值提炼 支撑精准服务与科学管理6 实时感知 辅助城市治理高效运行7 大数据资源平台目标体系规划11 建设目标与思路12 使能高效协同&#xff0…

PLM听过很多遍,却依旧不知道是什么?看完这篇你就懂

上周参加展会&#xff0c;很多客户在现场了解到e企拆图解决方案后&#xff0c;向我们咨询了很多问题&#xff0c;发现有几个名词经常被提及&#xff0c;比如PLM、PDM、BOM等。随着技术的爆炸发展&#xff0c;新的名词概念也与日俱增&#xff0c;对于这些名词&#xff0c;可能我…

Sa-Token源码简单阅读

一.权限登录模块包括几个基本子模块&#xff1a; 1.登录。 实现方式大致为&#xff1a;先检验用户名密码是否正确&#xff0c;如正确则在缓存中存入用户信息&#xff08;一般必须要有用户标识和访问token&#xff0c;或再加一些附加信息如用户的角色权限&#xff09;&#xf…

【unity细节】—(Can‘t add script)脚本文件无法拖拽到对象的问题

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏&#xff1a;unity细节和bug ⭐关于脚本文件无法拖拽到对象的问题⭐ 文章目录 ⭐关于脚本文件无法拖拽到对象的…

不得不说的结构型模式-装饰器模式

目录 装饰器模式是什么 下面是装饰器模式的一个通用的类图&#xff1a; 以下是使用C实现装饰器模式的示例代码&#xff1a; 下面是面试中关于桥接器模式的常见的问题&#xff1a; 下面是问题的答案&#xff1a; 装饰器模式是什么 装饰器模式是一种结构型设计模式&#xff…

苹果手机怎么看生产日期?参考方法在这!

案例&#xff1a;怎么查苹果手机买了几年&#xff1f; 【求助&#xff01;我从别人那里买了一部苹果手机&#xff08;非官方&#xff09;&#xff0c;怎么看这个手机用了几年&#xff1f;】 苹果手机作为一款高端手机&#xff0c;备受用户的喜爱。然而&#xff0c;许多用户不知…

Baumer工业相机堡盟工业相机如何通过BGAPI SDK获取每张图像的微秒时间和FrameID(C#)

BGAPI SDK获取图像微秒级时间和FrameID Baumer工业相机Baumer工业相机FrameID技术背景一、FrameID是什么&#xff1f;二、使用BGAPI SDK获取图像微秒时间和FrameID步骤 1.获取SDK图像微秒级时间2.获取SDK图像FrameIDBaumer工业相机使用微秒级时间和FrameID保存的用处Baumer工业…

全网唯一!Matlab世界顶尖艺术品配色包Rmetbrewer

想要绘制一幅颜色搭配合理、好看又不花哨的论文插图&#xff0c;该如何操作呢&#xff1f; 正所谓求其上者得其中&#xff0c;求其中者得其下。 那么&#xff0c;向高手借鉴思路&#xff0c;无疑是一种不落下乘的好策略。 而在色彩搭配领域&#xff0c;像莫奈、梵高这些世界…

操作系统原理 —— 进程有哪几种状态?状态之间如何切换?(七)

进程的五种状态 首先我们一起来看一下进程在哪些情况下&#xff0c;会有不同的状态表示。 创建态、就绪态 当我们刚开始运行程序的时候&#xff0c;操作系统把可执行文件加载到内存的时候&#xff0c;进程正在被创建的时候&#xff0c;它的状态是创建态&#xff0c;在这个阶…

三菱GX Works2梯形图程序分段显示设置的具体方法示例

三菱GX Works2梯形图程序分段显示设置的具体方法示例 大家平时在使用GX Works2进行梯形图程序编辑时,默认是一整段在一起,程序步数较多时查看起来不是那么方便,下面就和大家分享如何通过声明编辑来实现程序分段显示。 具体方法可参考以下内容: 如下图所示,打开GX Works2编…

DATAFAKER 使用方法记录

DATAFAKER 使用方法记录 win10 64位 Python 3.10.11 参考网址 datafaker的使用–详细教程 https://blog.csdn.net/A15517340610/article/details/105623103 https://github.com/gangly/datafaker python 版本 It is compatible with python2.7 and python3.4 也就是说 他…

案例2:Java图书商城系统设计与实现开题报告

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

使用nginx做WSS转为WS

HTTPS 是一种加密文本的超链接&#xff0c;所以需要证书&#xff0c;证书可以 使用域名&#xff0c;在腾讯云等服务商申请 https 证书&#xff0c;证书有 收费的和免费的&#xff0c;免费的有使用期限。 利用域名申请证书后&#xff0c;一般会有4中证书文件&#xff0c; .csr…

【Vue 基础】尚品汇项目-02-路由组件的搭建

项目路由说明&#xff1a; 前端的路由&#xff1a;Key-Value键值对 Key&#xff1a;URL&#xff08;地址栏中的路径&#xff09; Value&#xff1a;相应的路由组件 作用&#xff1a;设定访问路径&#xff0c;并将路径和组件映射起来&#xff08;就是用于局部刷新页面&#xff0…

前有谷歌的“生存指南”,后有金山系的“表格编程”,均登热榜

谷歌的“生存指南” 一位曾经在谷歌工作的工程师&#xff0c;干了一件了不起的事&#xff0c;花费了两年的时间&#xff0c;整理了一份“xg2xg”的清单。 原来这位离职的谷歌工程师为程序员编写了一份“厂外生存指南”&#xff0c;即使你从谷歌离职后&#xff0c;在这套“生存…