SpringBoot利用限速器RateLimiter实现单机限流的示例代码

目录
  • 一. 概述
  • 二. SpringBootDemo
    • 2.1 依赖
    • 2.2 application.yml
    • 2.3 启动类
    • 2.4 定义一个限流注解 RateLimiter.java
    • 2.5 代理: RateLimiterAspect.java
    • 2.6 使用

一. 概述

参考开源项目https://github.com/xkcoding/spring-boot-demo

在系统运维中, 有时候为了避免用户的恶意刷接口, 会加入一定规则的限流, 本Demo使用速率限制器com.xkcoding.ratelimit.guava.annotation.RateLimiter实现单机版的限流

二. SpringBootDemo

2.1 依赖

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
    </dependency>

    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
    </dependency>

2.2 application.yml

server:
  port: 8080
  servlet:
    context-path: /demo

2.3 启动类

@SpringBootApplication
public class SpringBootDemoRatelimitGuavaApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoRatelimitGuavaApplication.class, args);
    }
}

2.4 定义一个限流注解 RateLimiter.java

注意代码里使用了 AliasFor 设置一组属性的别名,所以获取注解的时候,需要通过 Spring 提供的注解工具类 AnnotationUtils 获取,不可以通过 AOP 参数注入的方式获取,否则有些属性的值将会设置不进去。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimiter {
    int NOT_LIMITED = 0;

    /**
     * qps (每秒并发量)
     */
    @AliasFor("qps") double value() default NOT_LIMITED;

    /**
     * qps (每秒并发量)
     */
    @AliasFor("value") double qps() default NOT_LIMITED;

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

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

2.5 代理: RateLimiterAspect.java

@Slf4j
@Aspect
@Component
public class RateLimiterAspect {
    /**
     * 单机缓存
     */
    private static final ConcurrentMap<String, com.google.common.util.concurrent.RateLimiter> RATE_LIMITER_CACHE = new ConcurrentHashMap<>();

    @Pointcut("@annotation(com.xkcoding.ratelimit.guava.annotation.RateLimiter)")
    public void rateLimit() {

    }

    @Around("rateLimit()")
    public Object pointcut(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        // 通过 AnnotationUtils.findAnnotation 获取 RateLimiter 注解
        RateLimiter rateLimiter = AnnotationUtils.findAnnotation(method, RateLimiter.class);
        if (rateLimiter != null && rateLimiter.qps() > RateLimiter.NOT_LIMITED) {
            double qps = rateLimiter.qps();
            // TODO 这个key可以根据具体需求配置,例如根据ip限制,或用户
            String key = method.getDeclaringClass().getName() + StrUtil.DOT + method.getName();
            if (RATE_LIMITER_CACHE.get(key) == null) {
                // 初始化 QPS
                RATE_LIMITER_CACHE.put(key, com.google.common.util.concurrent.RateLimiter.create(qps));
            }

            // 尝试获取令牌
            if (RATE_LIMITER_CACHE.get(key) != null && !RATE_LIMITER_CACHE.get(key).tryAcquire(rateLimiter.timeout(), rateLimiter.timeUnit())) {
                throw new RuntimeException("手速太快了,慢点儿吧~");
            }
        }
        return point.proceed();
    }
}

2.6 使用

@Slf4j
@RestController
public class TestController {

    /**
     * 接口每秒只能请求一次,不等待
     * @return
     */
    @RateLimiter(value = 1.0)
    @GetMapping("/test1")
    public Dict test1() {
        log.info("【test1】被执行了。。。。。");
        return Dict.create().set("msg", "hello,world!").set("description", "别想一直看到我,不信你快速刷新看看~");
    }

    /**
     * 接口每秒只能请求一次,等待一秒
     * @return
     */
    @RateLimiter(value = 1.0, timeout = 1,timeUnit = TimeUnit.SECONDS)
    @GetMapping("/test3")
    public Dict test3() {
        log.info("【test3】被执行了。。。。。");
        return Dict.create().set("msg", "hello,world!").set("description", "别想一直看到我,不信你快速刷新看看~");
    }
}

到此这篇关于SpringBoot利用限速器RateLimiter实现单机限流的示例代码的文章就介绍到这了,更多相关SpringBoot 单机限流 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解Springboot分布式限流实践

    高并发访问时,缓存.限流.降级往往是系统的利剑,在互联网蓬勃发展的时期,经常会面临因用户暴涨导致的请求不可用的情况,甚至引发连锁反映导致整个系统崩溃.这个时候常见的解决方案之一就是限流了,当请求达到一定的并发数或速率,就进行等待.排队.降级.拒绝服务等... 限流算法介绍 a.令牌桶算法 令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务. 当桶满时,新添加的令牌被丢弃或拒绝. b.漏桶算法 其主要目的是控制

  • springboot+redis 实现分布式限流令牌桶的示例代码

    1.前言 网上找了很多redis分布式限流方案,要不就是太大,需要引入第三方jar,而且还无法正常运行,要不就是定时任务定时往key中放入数据,使用的时候调用,严重影响性能,所以着手自定义实现redis令牌桶. 只用到了spring-boot-starter-data-redis包,并且就几行代码. 2.环境准备 a.idea新建springboot项目,引入spring-data-redis包 b.编写令牌桶实现方法RedisLimitExcutor c.测试功能,创建全局拦截器,测试功能 3

  • SpringBoot服务上实现接口限流的方法

    Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面. 在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制单位时间内接口访问次数:或者按照某种规则进行限流,如限制ip的单位时间访问次数等. 之前我们已经讲过接口限流的工具类ratelimter可以实现令牌桶的限流,很明显sentinel的功能更为全面和完善.来看一下sentinel的简介: https://github.com/spring-cloud-incubator/spring-cloud-alibab

  • 详解Springboot集成sentinel实现接口限流入门

    Sentinel是阿里巴巴开源的限流器熔断器,并且带有可视化操作界面. 在日常开发中,限流功能时常被使用,用于对某些接口进行限流熔断,譬如限制单位时间内接口访问次数:或者按照某种规则进行限流,如限制ip的单位时间访问次数等. 之前我们已经讲过接口限流的工具类ratelimter可以实现令牌桶的限流,很明显sentinel的功能更为全面和完善.来看一下sentinel的简介: https://github.com/spring-cloud-incubator/spring-cloud-alibab

  • SpingBoot中使用Redis对接口进行限流的实现

    目录 实现的思路 使用 Hash 存储接口的限流配置 使用普通kv,存储api的请求次数 使用SpringBoot实现 RedisKeys ObjectRedisTemplate RedisConfigration RequestLimitConfig RequestLimitInterceptor Controller WebMvcConfigration 最后一些问题 怎么灵活的配置 针对指定的用户限流 Restful 接口的问题 一个基于Redis实现的接口限流方案,先说要实现的功能 可以

  • Springboot使用redis进行api防刷限流过程详解

    这篇文章主要介绍了Springboot使用redis进行api防刷限流过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 api限流的场景 限流的需求出现在许多常见的场景中 秒杀活动,有人使用软件恶意刷单抢货,需要限流防止机器参与活动 某api被各式各样系统广泛调用,严重消耗网络.内存等资源,需要合理限流 淘宝获取ip所在城市接口.微信公众号识别微信用户等开发接口,免费提供给用户时需要限流,更具有实时性和准确性的接口需要付费. api限流实

  • SpringBoot2.0+阿里巴巴Sentinel动态限流实战(附源码)

    Sentinel 是什么? 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性. Sentinel 具有以下特征: 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围).消息削峰填谷.集群流量控制.实时熔断下游不可用应用等. 完备的实时监控:Sentinel 同时提供实时的监控功能.您可以在控制台中看到接入应用的

  • Spring Boot接口限流的常用算法及特点

    前言 在一个高并发系统中对流量的把控是非常重要的,当巨大的流量直接请求到我们的服务器上没多久就可能造成接口不可用,不处理的话甚至会造成整个应用不可用. 那么何为限流呢?顾名思义,限流就是限制流量,就像你宽带包了1个G的流量,用完了就没了.通过限流,我们可以很好地控制系统的qps,从而达到保护系统的目的.本篇文章将会介绍一下常用的限流算法以及他们各自的特点. 算法介绍 计数器法 计数器法是限流算法里最简单也是最容易实现的一种算法.比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个.

  • SpringBoot利用限速器RateLimiter实现单机限流的示例代码

    目录 一. 概述 二. SpringBootDemo 2.1 依赖 2.2 application.yml 2.3 启动类 2.4 定义一个限流注解 RateLimiter.java 2.5 代理: RateLimiterAspect.java 2.6 使用 一. 概述 参考开源项目https://github.com/xkcoding/spring-boot-demo 在系统运维中, 有时候为了避免用户的恶意刷接口, 会加入一定规则的限流, 本Demo使用速率限制器com.xkcoding.r

  • Springboot使用redis实现接口Api限流的示例代码

    前言 该篇介绍的内容如题,就是利用redis实现接口的限流(  某时间范围内 最大的访问次数 ) . 正文 惯例,先看下我们的实战目录结构: 首先是pom.xml 核心依赖: <!--用于redis数据库连接--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId>

  • Springboot+Redis实现API接口限流的示例代码

    添加Redis的jar包. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 在application.yml中配置redis spring: ## Redis redis: database: 0 host: 127.0.0.1 p

  • SpringMVC 限流的示例代码

    在使用SpringBoot做接口访问如何做接口的限流,这里我们可以使用google的Guava包来实现,当然我们也可以自己实现限流,Guava中的限流是久经考验的我们没必需重新再去写一个,如果想了解限流原理的同学可以自己查阅一下相关的资料,本文不作过来说明噢. 使用说明 在项目中引入Guava相关包 http://mvnrepository.com/artifact/com.google.guava/guava/21.0 maven项目 <!-- https://mvnrepository.co

  • SpringBoot如何使用自定义注解实现接口限流

    目录 使用自定义注解实现接口限流 1.自定义限流注解 2.限流类型枚举类 3.限流 Lua 脚本 4.限流切面处理类 5.使用与测试 SpringBoot工程中限流方式 1.google的guava,令牌桶算法实现限流 2.interceptor+redis根据注解限流 使用自定义注解实现接口限流 在高并发系统中,保护系统的三种方式分别为:缓存,降级和限流. 限流的目的是通过对并发访问请求进行限速或者一个时间窗口内的的请求数量进行限速来保护系统,一旦达到限制速率则可以拒绝服务.排队或等待. 1.

  • spring 项目实现限流方法示例

    目录 01.为什么AUSTIN项目需要限流 02.如何实现限流? 03.代码设计 04.总结 01.为什么AUSTIN项目需要限流 众所周知,服务器能处理的请求数是有限的,如果请求量特别大,我们就可能需要做限流. 限流处理的姿势:要么就让请求等待,要么就把请求给扔了 从系统架构来看,我们的统一处理入口在austin-api接入层上,austin-api接入层做完简单的参数校验以及参数拼接后,就将请求转发到消息队列上了 按正常来说,因为接了消息队列且接入层没有什么耗时的操作,那对外的接口压力不大的

  • Springboot实现根据条件切换注入不同实现类的示例代码

    最近有个一需求需要根据外界环境的属性(操作系统 || yml属性 || 其他bean的状态) 来实现启动时注入两套不同的实现类, 实现切换. 实现启动时条件注入分2步: 第一步 使用@Conditional(参数为 True false条件实现类 需要你自己实现)注解 @Conditional(RabbitMqCondition.class) public class RabbitmqSMSMsgServiceImpl extends RabbitmqBasicMsgService { // @

  • SpringBoot如何实现一个实时更新的进度条的示例代码

    前言 博主近期接到一个任务,大概内容是:导入excel表格批量修改状态,期间如果发生错误则所有数据不成功,为了防止重复提交,做一个类似进度条的东东. 那么下面我会结合实际业务对这个功能进行分析和记录. 正文 思路 前端使用bootstrap,后端使用SpringBoot分布式到注册中心,原先的想法是导入表格后异步调用修改数据状态的方法,然后每次计算修改的进度然后存放在session中,前台jquery写定时任务访问获取session中的进度,更新进度条进度和百分比.但是这存在session在服务

  • SpringBoot中时间类型 序列化、反序列化、格式处理示例代码

    [SpringBoot] 中时间类型 序列化.反序列化.格式处理 Date yml全局配置 spring: jackson: time-zone: GMT+8 date-format: yyyy-MM-dd HH:mm:ss #配置POST请求Body中Date时间类型序列化格式处理,并返回 请求参数类型转换 /** * 时间Date转换 * 配置GET请求,Query查询Date时间类型参数转换 */ @Component public class DateConverter implemen

随机推荐