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 sentinel 频繁主备切换的问题
Apr 12 Redis
深入浅析Redis 集群伸缩原理
May 15 Redis
在redisCluster中模糊获取key方式
Jul 09 Redis
分布式架构Redis中有哪些数据结构及底层实现原理
Mar 13 Redis
redis击穿 雪崩 穿透超详细解决方案梳理
Mar 17 Redis
高并发下Redis如何保持数据一致性(避免读后写)
Mar 18 Redis
Redis 哨兵机制及配置实现
Mar 25 Redis
一文搞懂Redis中String数据类型
Apr 03 Redis
Redis高并发缓存架构性能优化
May 15 Redis
Redis基本数据类型Set常用操作命令
Jun 01 Redis
redis protocol通信协议及使用详解
Jul 15 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
非洲第一个咖啡超凡杯大赛承办国—卢旺达的咖啡怎么样
2021/03/03 咖啡文化
phpwind中的数据库操作类
2007/01/02 PHP
js限制checkbox勾选的个数以及php获取多个checkbbox的方法深入解析
2013/07/18 PHP
PHPExcel读取EXCEL中的图片并保存到本地的方法
2015/02/14 PHP
laravel框架关于搜索功能的实现
2018/03/15 PHP
关于Yii中模型场景的一些简单介绍
2019/09/22 PHP
jquery 简单导航实现代码
2009/09/11 Javascript
jquery pagination插件实现无刷新分页代码
2009/10/13 Javascript
JS 树形递归实例代码
2010/05/18 Javascript
jQuery实现动态添加和删除一个div
2015/08/12 Javascript
jQuery siblings()用法实例详解
2016/04/26 Javascript
后端接收不到AngularJs中$http.post发送的数据原因分析及解决办法
2016/07/05 Javascript
JSONP和批量操作功能的实现方法
2016/08/21 Javascript
vue过渡和animate.css结合使用详解
2017/06/14 Javascript
Javascript中this关键字指向问题的测试与详解
2017/08/11 Javascript
clipboard.js在移动端复制失败的解决方法
2018/06/13 Javascript
微信小程序实现聊天对话(文本、图片)功能
2018/07/06 Javascript
一些手写JavaScript常用的函数汇总
2019/04/16 Javascript
Nodejs文件上传、监听上传进度的代码
2020/03/27 NodeJs
[46:55]完美世界DOTA2联赛决赛 FTD vs Phoenix 第三场 11.08
2020/11/11 DOTA
TensorFlow深度学习之卷积神经网络CNN
2018/03/09 Python
Python中的并发处理之asyncio包使用的详解
2018/04/03 Python
python3使用SMTP发送HTML格式邮件
2018/06/19 Python
Python urllib request模块发送请求实现过程解析
2020/12/10 Python
详解CSS3选择器的使用方法汇总
2015/11/24 HTML / CSS
香港连卡佛百货官网:Lane Crawford
2019/09/04 全球购物
医务人员竞聘职务自我评价分享
2013/11/08 职场文书
高中毕业自我鉴定
2013/12/16 职场文书
八年级美术教学反思
2014/02/02 职场文书
行政主管职责范本
2014/03/07 职场文书
党员群众路线承诺书
2014/05/20 职场文书
初中军训感言
2015/08/01 职场文书
python实战之一步一步教你绘制小猪佩奇
2021/04/22 Python
只用50行Python代码爬取网络美女高清图片
2021/06/02 Python
如何用Python搭建gRPC服务
2021/06/30 Python
Go语言 详解net的tcp服务
2022/04/14 Golang