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在直播场景的实践方案
Apr 27 Redis
为Java项目添加Redis缓存的方法
May 18 Redis
使用Redis实现实时排行榜功能
Jul 02 Redis
Redisson实现Redis分布式锁的几种方式
Aug 07 Redis
Redis+Lua脚本实现计数器接口防刷功能(升级版)
Feb 12 Redis
Redis 哨兵机制及配置实现
Mar 25 Redis
Redis基本数据类型List常用操作命令
Jun 01 Redis
浅谈Redis缓冲区机制
Jun 05 Redis
一文教你快速生成MySQL数据库关系图
Jun 28 Redis
Redis sentinel哨兵集群的实现步骤
Jul 15 Redis
Redis Lua脚本实现ip限流示例
Jul 15 Redis
Redis主从复制操作和配置详情
Sep 23 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获取某个目录大小的代码
2008/09/10 PHP
phpMyAdmin 安装配置方法和问题解决
2009/06/08 PHP
析构函数与php的垃圾回收机制详解
2013/10/28 PHP
PHP 快速排序算法详解
2014/11/10 PHP
php 伪造ip以及url来路信息方法汇总
2014/11/25 PHP
PHP爬虫之百万级别知乎用户数据爬取与分析
2016/01/22 PHP
基于PHP生成简单的验证码
2016/06/01 PHP
TP5框架页面跳转样式操作示例
2020/04/05 PHP
jQuery 学习6 操纵元素显示效果的函数
2010/02/07 Javascript
JQuery 1.6发布 性能提升,同时包含大量破坏性变更
2011/05/10 Javascript
含有CKEditor的表单如何提交
2014/01/09 Javascript
jquerymobile局部渲染的各种刷新方法小结
2014/03/05 Javascript
JQuery仿小米手机抢购页面倒计时效果
2014/12/16 Javascript
EasyUI中实现form表单提交的示例分享
2015/03/01 Javascript
基于Jquery制作图片文字排版预览效果附源码下载
2015/11/18 Javascript
jQuery ajax请求返回list数据动态生成input标签,并把list数据赋值到input标签
2016/03/29 Javascript
Bootstrap打造一个左侧折叠菜单的系统模板(一)
2016/05/17 Javascript
一个炫酷的Bootstrap导航菜单
2016/12/28 Javascript
javascript实现复选框全选或反选
2017/02/04 Javascript
实现图片首尾平滑轮播(JS原生方法—节流)
2017/10/17 Javascript
JavaScript实现的拼图算法分析
2019/02/13 Javascript
[52:03]DOTA2-DPC中国联赛 正赛 Ehome vs iG BO3 第三场 1月31日
2021/03/11 DOTA
Python内置模块hashlib、hmac与uuid用法分析
2018/02/12 Python
pandas or sql计算前后两行数据间的增值方法
2018/04/20 Python
用pycharm开发django项目示例代码
2019/06/13 Python
python如何调用字典的key
2020/05/25 Python
HTML5给汉字加拼音收起展开组件的实现代码
2020/04/08 HTML / CSS
Aurora London官网:奢华、负担得起的皮革手袋
2020/08/01 全球购物
浙江文明网签名寄语
2014/01/18 职场文书
英语教师自荐信
2014/05/26 职场文书
本科生求职信
2014/06/17 职场文书
音乐学专业求职信
2014/07/22 职场文书
乡镇八一建军节活动方案
2014/08/24 职场文书
2015教师年度思想工作总结
2015/04/30 职场文书
导游词之日月潭
2019/11/05 职场文书
SQL Server数据库查询出现阻塞之性能调优
2022/04/10 SQL Server