Redis+AOP+自定义注解实现限流


Posted in Redis onJune 28, 2022

Redis安装

一提到Redis,相信大家都不会感到陌生吧。今天就让我们在阿里云上安装一下Redis,为以后使用它做个准备。

下载

1,下载页面

2,下载

解压

tar -xzvf redis-5.0.7.tar.gz

准备编译

1, 请在操作前确认gcc是否已安装,gcc -v

如未安装,可以执行这个命令安装:yum install gcc

2,请在操作前确认tcl是否已安装如未安装,可以执行这个命令安装:yum install tcl

编译

[root@localhost source]# cd redis-5.0.7/
[root@localhost redis-5.0.7]# make MALLOC=libc

make 后加 MALLOC的参数的原因:

避免提示找不到 jemalloc/jemalloc.h

测试编译

[root@localhost redis-5.0.7]# make test

如果看到以下字样:表示无错误:\o/ All tests passed without errors!

安装

[root@localhost redis-5.0.7]# mkdir /usr/local/soft/redis5 可分步创建
[root@localhost redis-5.0.7]# cd /usr/local/soft/redis5/
[root@localhost redis5]# mkdir bin
[root@localhost redis5]# mkdir conf
[root@localhost redis5]# cd bin/

find / -name redis-cli 查找文件位置

[root@localhost bin]# cp /root/redis-5.0.7/src/redis-cli ./
[root@localhost bin]# cp /root/redis-5.0.7/src/redis-server ./
[root@localhost bin]# cd …/conf/
[root@localhost conf]# cp /root/redis-5.0.7/redis.conf ./

配置

[root@localhost conf]# vi redis.conf

设置以下两个地方:

# daemonize no 
 daemonize yes  
# maxmemory <bytes>
maxmemory 128MB

说明:分别是以daemon方式独立运行 / 内存的最大使用限制

运行

[root@localhost conf]# /usr/local/soft/redis5/bin/redis-server /usr/local/soft/redis5/conf/redis.conf

检查端口是否在使用中

[root@localhost conf]# netstat -anp | grep 6379
​​​​​​​tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 16073/redis-server

查看redis的当前版本:

[root@localhost conf]# /usr/local/soft/redis5/bin/redis-server -v
​​​​​​​Redis server v=5.0.7 sha=00000000:0 malloc=libc bits=64 build=8e31d2ed9a4c9593

使redis可以用systemd方式启动和管理

1,编辑service文件

[root@localhost liuhongdi]# vim /lib/systemd/system/redis.service

2,service文件内容:

[Unit]Description=RedisAfter=network.target
[Service]Type=forkingPIDFile=/var/run/redis_6379.pidExecStart=/usr/local/soft/redis5/bin/redis-server /usr/local/soft/redis5/conf/redis.confExecReload=/bin/kill -s HUP $MAINPIDExecStop=/bin/kill -s QUIT $MAINPIDPrivateTmp=true
[Install]WantedBy=multi-user.target

3.重载系统服务

[root@localhost liuhongdi]# systemctl daemon-reload

4,用来管理redis

启动

systemctl start redis

查看状态

systemctl status redis

使开机启动

systemctl enable redis

查看本地centos的版本:

[root@localhost lib]# cat /etc/redhat-release
CentOS Linux release 8.1.1911 (Core)

客户端连接redis

1、阿里云得设置redis.conf中的bind 后跟着的127.0.0.1修改为0.0.0.0,重启redis

2、开放端口:开放服务器的端口号,步骤如下:

打开实例列表,点击“ 更多”按钮,选择“ 网络和安全组 ”中的“安全组配置”,选择 “安全组列表”tab页面,点击 “配置规则”按钮,点击 “快速添加”按钮,勾选“Redis(6379)”,点击 “确定”之后就可以正常连接了。

3、给redis设置连接密码:

查找到# requirepass foobared 注释去掉并写入要设置的密码,例如:requirepass 123456

redis启动之后测试是否可以连接命令

./redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> auth 123456//此处是你的密码

注意: 如果是阿里云的话一定要设置密码,否则很可能被矿机程序注入定时任务,用你的服务器挖矿,阿里云一直会有信息提示你。

Redis限流

服务器上的Redis已经安装完成了(安装步骤见上文),今天就让我们使用Redis来做个小功能:自定义拦截器限制访问次数,也就是限流。

首先我们要在项目中引入Redis

1、引入依赖

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

<!-- redis依赖commons-pool 这个依赖一定要添加 -->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
</dependency>

2、application.yml配置

server:
port: 8181

spring:
redis:
  host: 127.0.0.1
  port: 6379
  timeout: 10s
  lettuce:
    pool:
    # 连接池中的最小空闲连接 默认0
      min-idle: 0
      # 连接池中的最大空闲连接 默认8
      max-idle: 8
      # 连接池最大连接数 默认8 ,负数表示没有限制
      max-active: 8
      # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认-1
      max-wait: -1ms
  #选择哪个库存储,默认是0
  database: 0
  password: 123456

3、创建redisConfig,引入redisTemplate

@Configuration
public class RedisConfig {
   @Bean
   public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
       RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
       redisTemplate.setKeySerializer(new StringRedisSerializer());
       redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
       redisTemplate.setHashKeySerializer(new StringRedisSerializer());
       redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
       redisTemplate.setConnectionFactory(redisConnectionFactory);
       return redisTemplate;
  }
}

自定义注解和拦截器

1、自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AccessLimit {
   int seconds(); //秒数
   int maxCount(); //最大访问次数
   boolean needLogin()default true;//是否需要登录
}

2、创建拦截器

@Component
public class FangshuaInterceptor extends HandlerInterceptorAdapter {

   @Autowired
   private RedisTemplate redisTemplate;

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       //判断请求是否属于方法的请求
       if(handler instanceof HandlerMethod){
           HandlerMethod hm = (HandlerMethod) handler;
           //获取方法中的注解,看是否有该注解
           AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
           if(accessLimit == null){
               return true;
          }
           int seconds = accessLimit.seconds();
           int maxCount = accessLimit.maxCount();
           boolean login = accessLimit.needLogin();
           String key = request.getRequestURI();
           //如果需要登录
           if(login){
               //获取登录的session进行判断,此处只是例子,不写具体的业务
               //.....
               key+=""+"1";  //这里假设用户是1,项目中是动态获取的userId
          }

           //从redis中获取用户访问的次数
           Integer count;
           if(Objects.isNull(redisTemplate.opsForValue().get(key))){
               count = 0;
          }else{
               count = (Integer) redisTemplate.opsForValue().get(key);
          }
           if(count == 0){
               redisTemplate.opsForValue().set(key,1,seconds, TimeUnit.SECONDS);
          }else if(count<maxCount){
               //key的值加1
               redisTemplate.opsForValue().increment(key);
          }else{
               //超出访问次数
               Map<String,Object> errMap=new HashMap<>();
               errMap.put("code",400);
               errMap.put("msg","请求超时,请稍后再试");
               render(response,errMap); //这里的CodeMsg是一个返回参数
               return false;
          }
      }
       return true;
  }


   private void render(HttpServletResponse response, Map<String,Object> errMap) throws Exception {
       response.setContentType("application/json;charset=UTF-8");
       OutputStream out = response.getOutputStream();
       String str = JSON.toJSONString(errMap);
       out.write(str.getBytes("UTF-8"));
       out.flush();
       out.close();
  }
}

3、将自定义拦截器加入到拦截器列表中

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

   @Autowired
   private FangshuaInterceptor interceptor;

   @Override
   public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(interceptor);
  }
}

最后做一下简单的测试

@RestController
@RequestMapping("test")
public class TestController {

   //每三十秒最多可以请求三次,不需要登录
   @AccessLimit(seconds=30, maxCount=3, needLogin=false)
   @PostMapping("/fangshua")
   public String fangshua(){
       return "成功";
  }
}

以上就是Redis+AOP+自定义注解实现限流的详细内容,更多关于Redis限流的资料请关注三水点靠木其它相关文章!


Tags in this post...

Redis 相关文章推荐
redis通过6379端口无法连接服务器(redis-server.exe闪退)
May 08 Redis
基于Redis延迟队列的实现代码
May 13 Redis
详解Redis集群搭建的三种方式
May 31 Redis
redis cluster支持pipeline的实现思路
Jun 23 Redis
Redis 彻底禁用RDB持久化操作
Jul 09 Redis
在项目中使用redis做缓存的一些思路
Sep 14 Redis
基于Redis结合SpringBoot的秒杀案例详解
Oct 05 Redis
Redis高并发防止秒杀超卖实战源码解决方案
Nov 01 Redis
CentOS8.4安装Redis6.2.6的详细过程
Nov 20 Redis
分布式架构Redis中有哪些数据结构及底层实现原理
Mar 13 Redis
Redis基本数据类型List常用操作命令
Jun 01 Redis
基于Redission的分布式锁实战
Aug 14 Redis
利用Redis实现点赞功能的示例代码
Jun 28 #Redis
一文教你快速生成MySQL数据库关系图
Jun 28 #Redis
Redis实现主从复制方式(Master&Slave)
Jun 21 #Redis
浅谈Redis变慢的原因及排查方法
使用Redis实现分布式锁的方法
Jun 16 #Redis
关于Redis的主从复制及哨兵问题
Jun 16 #Redis
Redis实现分布式锁的五种方法详解
You might like
PHP curl 并发最佳实践代码分享
2012/09/05 PHP
PHP IE中下载附件问题解决方法
2014/01/07 PHP
PHP 导出Excel示例分享
2014/08/18 PHP
微信支付开发告警通知实例
2016/07/12 PHP
二行代码解决全部网页木马
2008/03/28 Javascript
使用Microsoft Ajax Minifier减小JavaScript文件大小的方法
2010/04/01 Javascript
基于jquery的图片懒加载js
2010/06/30 Javascript
JQueryiframe页面操作父页面中的元素与方法(实例讲解)
2013/11/19 Javascript
javascript获取浏览器类型和版本的方法(js获取浏览器版本)
2014/03/13 Javascript
jquery禁用右键单击功能屏蔽F5刷新
2014/03/17 Javascript
Angularjs基础知识及示例汇总
2015/01/22 Javascript
javascript日期操作详解(脚本之家整理)
2015/09/05 Javascript
javascript入门教程基础篇
2015/11/16 Javascript
JS三级联动代码格式实例详解
2019/12/30 Javascript
vue下拉刷新组件的开发及slot的使用详解
2020/12/23 Vue.js
[13:39]2014 DOTA2华西杯精英邀请赛 5 25 NewBee VS DK第一场
2014/05/26 DOTA
[44:09]DOTA2上海特级锦标赛A组小组赛#1 EHOME VS MVP.Phx第二局
2016/02/25 DOTA
基于python实现微信模板消息
2015/12/21 Python
让python 3支持mysqldb的解决方法
2017/02/14 Python
Python模拟三级菜单效果
2017/09/11 Python
django rest framework之请求与响应(详解)
2017/11/06 Python
使用TensorFlow搭建一个全连接神经网络教程
2020/02/06 Python
python查找特定名称文件并按序号、文件名分行打印输出的方法
2020/04/24 Python
Opencv求取连通区域重心实例
2020/06/04 Python
详解numpy1.19.4与python3.9版本冲突解决
2020/12/15 Python
CSS实现半透明边框与多重边框的场景分析
2019/11/13 HTML / CSS
HTML5离线缓存在tomcat下部署可实现图片flash等离线浏览
2012/12/13 HTML / CSS
Rakuten Kobo台湾:电子书、eReaders和Reading应用程式
2017/11/24 全球购物
美国专业消费电子及摄影器材网站:B&H Photo Video
2019/12/18 全球购物
Windows和Linux动态库应用异同
2016/04/17 面试题
影视艺术学院毕业生自荐信
2013/11/13 职场文书
母亲80寿诞答谢词
2014/01/16 职场文书
大学生求职工作的自我评价
2014/02/13 职场文书
干货!开幕词的写作方法
2019/04/02 职场文书
MySQL之PXC集群搭建的方法步骤
2021/05/25 MySQL
使用react+redux实现计数器功能及遇到问题
2021/06/02 Javascript