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数据结构之链表与字典的使用
May 11 Redis
详解Redis集群搭建的三种方式
May 31 Redis
SpringBoot 集成Redis 过程
Jun 02 Redis
解析redis hash应用场景和常用命令
Aug 04 Redis
关于SpringBoot 使用 Redis 分布式锁解决并发问题
Nov 17 Redis
redis击穿 雪崩 穿透超详细解决方案梳理
Mar 17 Redis
Redis官方可视化工具RedisInsight安装使用教程
Apr 19 Redis
解决 redis 无法远程连接
May 15 Redis
Redis实现短信验证码登录的示例代码
Jun 14 Redis
关于Redis的主从复制及哨兵问题
Jun 16 Redis
使用Redis实现分布式锁的方法
Jun 16 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函数解决SQL injection
2006/10/09 PHP
PHP has encountered an Access Violation
2007/01/15 PHP
解析ajax事件的调用顺序
2013/06/17 PHP
PHP图片等比缩放类SimpleImage使用方法和使用实例分享
2014/04/10 PHP
javascript XML数据显示为HTML一例
2008/12/23 Javascript
ExtJS GTGrid 简单用户管理
2009/07/01 Javascript
学习ExtJS(二) Button常用方法
2009/10/07 Javascript
利用location.hash实现跨域iframe自适应
2010/05/04 Javascript
javascript 数据类型转换(parseInt,parseFloat)
2010/07/20 Javascript
js贪吃蛇网页版游戏特效代码分享(挑战十关)
2015/08/24 Javascript
jQuery插件开发汇总
2016/05/15 Javascript
Angular.js 实现数字转换汉字实例代码
2016/07/14 Javascript
完美解决IE不支持Data.parse()的问题
2016/11/24 Javascript
在vue项目中使用sass的配置方法
2018/03/20 Javascript
JS中移除非数字最多保留一位小数
2018/05/09 Javascript
vue-cli2.x项目优化之引入本地静态库文件的方法
2018/06/19 Javascript
微信小程序实现传递多个参数与事件处理
2019/08/12 Javascript
纯异步nodejs文件夹(目录)复制功能
2019/09/03 NodeJs
vue改变循环遍历后的数据实例
2019/11/07 Javascript
VueCli生产环境打包部署跨域失败的解决
2020/11/13 Javascript
Python实现简单石头剪刀布游戏
2021/01/20 Python
python pickle存储、读取大数据量列表、字典数据的方法
2019/07/07 Python
Python pandas实现excel工作表合并功能详解
2019/08/29 Python
python 五子棋如何获得鼠标点击坐标
2019/11/04 Python
python GUI库图形界面开发之PyQt5信号与槽事件处理机制详细介绍与实例解析
2020/03/08 Python
python对指定字符串逆序的6种方法(小结)
2020/04/02 Python
Python中如何添加自定义模块
2020/06/09 Python
爬虫代理的cookie如何生成运行
2020/09/22 Python
校本教研工作制度
2014/01/22 职场文书
新员工试用期自我鉴定
2014/04/17 职场文书
英语演讲稿3分钟
2014/04/29 职场文书
放飞梦想演讲稿800字
2014/08/26 职场文书
2015中学政教处工作总结
2015/07/22 职场文书
小学数学教师研修日志
2015/11/13 职场文书
Python 读写 Matlab Mat 格式数据的操作
2021/05/19 Python
HttpClient实现文件上传功能
2022/08/14 Java/Android