我的编程空间,编程开发者的网络收藏夹
学习永远不晚

SpingBoot中怎么利用Redis对接口限流

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

SpingBoot中怎么利用Redis对接口限流

这期内容当中小编将会给大家带来有关SpingBoot中怎么利用Redis对接口限流,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

实现的思路

使用 Hash 存储接口的限流配置

request_limit_config    "/api2" : {"limit": 10, "time": 1, "timeUnit": "SECONDS"}

hash中的key就是请求的uri路径,value是一个对象。通过3个属性,描述限制策略

  • limit 最多请求次数

  • time 时间

  • timeUnit 时间单位

使用普通kv,存储api的请求次数

request_limit:/api  1

处理请求的时候,通过increment对该key进行 +1 操作,如果返回1,则表示是第一次请求,此时设置它的过期时间。为限制策略中定义时间限制信息。再通过命名的返回值,判断是否超出了限制。

increment 指令是线程安全的,不用担心并发的问题。

使用SpringBoot实现

创建SpringBoot工程,添加

spring-boot-starter-data-redis依赖,并且给出正确的配置。

这里不做工程的创建,配置,以及其他额外代码的演示,仅仅给出关键的代码。

RedisKeys

定义两个Key,限流用到的2个Key

public interface RedisKeys {        String REQUEST_LIMIT_CONFIG = "request_limit_config";        String REQUEST_LIMIT = "request_limit";}

ObjectRedisTemplate

为了提高hash value的序列化效率,自定义一个RedisTemplate的实现。使用jdk的序列化,而不是json。

import org.springframework.data.redis.core.RedisTemplate;public class ObjectRedisTemplate extends RedisTemplate<String, Object> {}

RedisConfigration

把自定义的ObjectRedisTemplate配置到IOC

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.serializer.RedisSerializer;import io.springboot.jwt.redis.ObjectRedisTemplate;@Configurationpublic class RedisConfiguration {    @Bean    public ObjectRedisTemplate objectRedisTemplate(@Autowired RedisConnectionFactory redisConnectionFactory) {        ObjectRedisTemplate objectRedisTemplate = new ObjectRedisTemplate();        objectRedisTemplate.setConnectionFactory(redisConnectionFactory);        objectRedisTemplate.setKeySerializer(RedisSerializer.string());        objectRedisTemplate.setValueSerializer(RedisSerializer.java());        // hash的key使用String序列化        objectRedisTemplate.setHashKeySerializer(RedisSerializer.string());        // hash的value使用jdk的序列化        objectRedisTemplate.setHashValueSerializer(RedisSerializer.java());        return objectRedisTemplate;    }}

RequestLimitConfig

用于描述限制策略的对象。

import java.io.Serializable;import java.util.concurrent.TimeUnit;public class RequestLimitConfig implements Serializable {        private static final long serialVersionUID = 1101875328323558092L;    // 最大请求次数    private long limit;    // 时间    private long time;    // 时间单位    private TimeUnit timeUnit;    public RequestLimitConfig() {        super();    }    public RequestLimitConfig(long limit, long time, TimeUnit timeUnit) {        super();        this.limit = limit;        this.time = time;        this.timeUnit = timeUnit;    }    public long getLimit() {        return limit;    }    public void setLimit(long limit) {        this.limit = limit;    }    public long getTime() {        return time;    }    public void setTime(long time) {        this.time = time;    }    public TimeUnit getTimeUnit() {        return timeUnit;    }    public void setTimeUnit(TimeUnit timeUnit) {        this.timeUnit = timeUnit;    }    @Override    public String toString() {        return "RequestLimitConfig [limit=" + limit + ", time=" + time + ", timeUnit=" + timeUnit + "]";    }}

RequestLimitInterceptor

通过拦截器,来完成限流的实现。

import java.nio.charset.StandardCharsets;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.MediaType;import org.springframework.util.StringUtils;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import io.springboot.jwt.redis.ObjectRedisTemplate;import io.springboot.jwt.redis.RedisKeys;import io.springboot.jwt.web.RequestLimitConfig;public class RequestLimitInterceptor extends HandlerInterceptorAdapter {    private static final Logger LOGGER = LoggerFactory.getLogger(RequestLimitInterceptor.class);    @Autowired    private ObjectRedisTemplate objectRedisTemplate;    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {                String contentPath = request.getContextPath();        String uri = request.getRequestURI().toString();        if (!StringUtils.isEmpty(contentPath) && !contentPath.equals("/")) {            uri =  uri.substring(uri.indexOf(contentPath) + contentPath.length());        }        LOGGER.info("uri={}",  uri);                RequestLimitConfig requestLimitConfig = (RequestLimitConfig) this.objectRedisTemplate.opsForHash().get(RedisKeys.REQUEST_LIMIT_CONFIG, uri);        if (requestLimitConfig == null) {            LOGGER.info("该uri={}没有限流配置", uri);            return true;        }        String limitKey = RedisKeys.REQUEST_LIMIT + ":" + uri;                long count = this.objectRedisTemplate.opsForValue().increment(limitKey);        if (count == 1) {                        this.objectRedisTemplate.expire(limitKey, requestLimitConfig.getTime(), requestLimitConfig.getTimeUnit());            LOGGER.info("设置过期时间:time={}, timeUnit={}", requestLimitConfig.getTime(), requestLimitConfig.getTimeUnit());        }        LOGGER.info("请求限制。limit={}, count={}", requestLimitConfig.getLimit(), count);        if (count > requestLimitConfig.getLimit()) {                        response.setContentType(MediaType.TEXT_PLAIN_VALUE);            response.setCharacterEncoding(StandardCharsets.UTF_8.name());            response.getWriter().write("服务器繁忙,稍后再试");            return false;        }        return true;    }}

Controller

一个用于测试的接口类

import java.util.Collections;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/test")public class TestController {    @GetMapping    public Object test () {        return Collections.singletonMap("success", true);    }}

WebMvcConfigration

拦截器的配置

import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import io.springboot.jwt.web.interceptor.RequestLimitInterceptor;@Configurationpublic class WebMvcConfiguration implements WebMvcConfigurer {    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(this.requestLimitInterceptor())            .addPathPatterns("/test");    }    @Bean    public RequestLimitInterceptor requestLimitInterceptor() {        return new RequestLimitInterceptor();    }}

通过@Test测试,初始化一个限流配置

@Autowiredprivate ObjectRedisTemplate objectRedisTemplate;@Testpublic void test () {    // 3秒内,只能请求2次    RequestLimitConfig requestLimitConfig = new RequestLimitConfig(2, 3, TimeUnit.SECONDS);    // 限制的uri是 /test    this.objectRedisTemplate.opsForHash().put(RedisKeys.REQUEST_LIMIT_CONFIG, "/test", requestLimitConfig);}

使用浏览器演示

SpingBoot中怎么利用Redis对接口限流

最后一些问题

怎么灵活的配置

都写到这个份儿上了,如果熟悉Redis以及客户端,我想提供一个“限流管理”接口的并不是难事儿。

针对指定的用户限流

这里演示的方法是,针对接口的限流。有时候,也有一些特殊的需求,需要“针对不同”的用户来做限流。打个比方。针对A用户,允许有他1分钟请求20次接口,针对B用户,允许他1分钟请求10次接口。 这个其实也简单,只需要修改一下上面的两个限制key,在key中添加用户的唯一标识(例如:ID)

request_limit_config    "/api2:{userId}" : {"limit": 10, "time": 1, "timeUnit": "SECONDS"}
request_limit:{userId}:/api  1

在拦截器中获取到用户的ID,加上用户ID进行检索和判断,就可以完成针对用户的限流。

Restful 接口的问题

@GetMapping("/user/{id}")  // restful的检索接口,往往把ID信息放在了URI中

这就会导致上面的代码有问题,因为这里采用的是根据URI来完成的限流操作。检索不同ID的用户,会导致URI不同。 解决办法我认为也很简单。那就不要使用URI,可以通过 自定义注解,方式,不同的接口,定义不同的唯一标识。在拦截器中获取到注解,读取到唯一的编码,代替原来的URI,即可。

上述就是小编为大家分享的SpingBoot中怎么利用Redis对接口限流了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

SpingBoot中怎么利用Redis对接口限流

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SpingBoot中怎么利用Redis对接口限流

这期内容当中小编将会给大家带来有关SpingBoot中怎么利用Redis对接口限流,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。实现的思路使用 Hash 存储接口的限流配置request_limit_co
2023-06-20

Java怎么使用Semaphore对单接口进行限流

这篇文章主要讲解了“Java怎么使用Semaphore对单接口进行限流”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java怎么使用Semaphore对单接口进行限流”吧!目录一、实战说明1
2023-06-20

SpringBoot中怎么利用Sentinel实现接口流量控制

这期内容当中小编将会给大家带来有关SpringBoot中怎么利用Sentinel实现接口流量控制,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。项目搭建首先我们来创建一个测试项目,这里初始化项目的url建议
2023-06-15

Springboot怎么利用Redis实现接口幂等性拦截

今天小编给大家分享一下Springboot怎么利用Redis实现接口幂等性拦截的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
2023-07-02

怎么在java中利用default操作接口

怎么在java中利用default操作接口?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。常用的java框架有哪些1.SpringMVC,Spring Web MVC是一种基
2023-06-14

怎么在java中利用Semaphore实现一个限流器

怎么在java中利用Semaphore实现一个限流器?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Java可以用来干什么Java主要应用于:1. web开发;2
2023-06-14

VB.NET中怎么利用接口实现多态

VB.NET中怎么利用接口实现多态,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。VB.NET接口实现多态的实现,能够通过使用多接口,用户可以在不中断运行代码的情
2023-06-17

Spring中的bean怎么利用Aware接口获取

这期内容当中小编将会给大家带来有关Spring中的bean怎么利用Aware接口获取,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。在使用spring编程时,常常会遇到想根据bean的名称来获取相应的bea
2023-05-31

C#中怎么利用类实现一个接口

这篇文章给大家介绍C#中怎么利用类实现一个接口,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。C#类实现接口前面我们已经说过,接口定义不包括方法的实现部分。接口可以通过类或结构来实现。我们主要讲述通过类来实现接口。用类来
2023-06-17

Java中怎么利用Swagger配置扫描接口

本篇文章为大家展示了Java中怎么利用Swagger配置扫描接口,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1. Swagger--配置扫描接口及开关1.1 配置扫描接口SwaggerConfig
2023-06-20

Java 中怎么利用Runnable线程编写接口

本篇文章为大家展示了Java 中怎么利用Runnable线程编写接口,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。将我们的线程代码写入其中,就完成了这一部分 的任务。但是Runnable接口并没有任
2023-06-17

Java中怎么利用接口来创建代理

Java中怎么利用接口来创建代理?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。首先创建工厂bean,就是用来返回代理的FactoryBeanimport org.sprin
2023-06-15

JAVA中的HTTPS接口怎么利用HttpClient进行调用

JAVA中的HTTPS接口怎么利用HttpClient进行调用?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1.为了避免需要证书,所以用一个类继承DefaultHttpClie
2023-05-31

mybatis中的mapper.xml文件怎么利用接口查找

这篇文章给大家介绍mybatis中的mapper.xml文件怎么利用接口查找,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。在使用mybatis的时候,有一种方式是BookMapper bookMapper = SqlS
2023-05-31

Java8中怎么利用Stream实现函数式接口

这期内容当中小编将会给大家带来有关Java8中怎么利用Stream实现函数式接口,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。函数式接口什么是函数式接口?简单来说就是只有一个抽象函数的接口。为了使得函数式
2023-06-16

怎么在接口回调中的使用接口对象的实例化

本篇文章为大家展示了怎么在接口回调中的使用接口对象的实例化,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。接口回调:可以把实现某一接口类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调
2023-05-31

Android应用中怎么对接口进行传参

Android应用中怎么对接口进行传参?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Android源码中常用的接口传参实例详解把MyCclass中的参数传到MyDclass/*
2023-05-31

怎么在SpringBoot中利用Feign调用其他服务接口

本篇文章给大家分享的是有关怎么在SpringBoot中利用Feign调用其他服务接口,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。引入依赖