springboot高级教程基于 redis 通过注解实现限流

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: springboot高级教程基于 redis 通过注解实现限流

Spring Boot整合Redis有一种方便的方式是使用注解方式实现限流。


可以通过自定义注解的方式来标注需要限流的方法,在方法执行前进行限流的检查。


以下是具体实现方式:


1. 自定义注解`@RedisLimit`,并定义注解元素,如限流的时间、限流的次数等。

2. 编写切面类`RedisLimitAspect`,在方法执行前调用`RedisLimit`组件实现限流。

3. 将`RedisLimitAspect`类加入Spring容器中,以便进行注入。

4. 在需要进行限流的方法上添加`@RedisLimit`注解。


以下是示例代码:


`@RedisLimit`注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLimit {
    int limit() default 10;
    int timeout() default 60;
    String key() default "";
}


切面类`RedisLimitAspect`:


    @Aspect
    @Component
    public class RedisLimitAspect {
        @Autowired
        private RedisTemplate<String, String> redisTemplate;
        @Pointcut("@annotation(redisLimit)")
        public void pointcut(RedisLimit redisLimit) {}
        @Before("pointcut(redisLimit)")
        public void before(JoinPoint joinPoint, RedisLimit redisLimit) throws Throwable {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                    .getRequest();
            String ip = IpUtils.getRequestIp(request);
            String key = redisLimit.key().equals("") ? ip : redisLimit.key();
            int limit = redisLimit.limit();
            int timeout = redisLimit.timeout();
            if (!redisLimit(redisTemplate, key, limit, timeout)) {
                throw new RuntimeException("限流了");
            }
        }
        /**
         * 判断Redis中的key对应的值,是否满足小于limit
         *
         * @param redisTemplate RedisTemplate
         * @param key           键
         * @param limit         限流次数
         * @param timeout       超时时间(秒)
         * @return 是否限流
         */
        private boolean redisLimit(RedisTemplate<String, String> redisTemplate, String key, int limit, int timeout) {
            String value = String.valueOf(System.currentTimeMillis() / 1000);
            try {
                redisTemplate.watch(key);
                List<String> list = redisTemplate.opsForList().range(key, 0, -1);
                int count = 0;
                if (list != null && !list.isEmpty()) {
                    for (String time : list) {
                        if (Long.parseLong(time) >= (System.currentTimeMillis() / 1000 - timeout)) {
                            count++;
                        } else {
                            redisTemplate.opsForList().trim(key, count, -1);
                            break;
                        }
                    }
                }
                if ((count + 1) > limit) {
                    return false;
                }
                redisTemplate.multi();
                redisTemplate.opsForList().rightPush(key, value);
                redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
                redisTemplate.exec();
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            } finally {
                redisTemplate.unwatch();
            }
            return true;
        }
    }


    在需要进行限流的方法上添加`@RedisLimit`注解:


      @RestController
      public class TestController {
          @GetMapping("/test")
          @RedisLimit(key = "testKey", limit = 5, timeout = 60)
          public String test() {
              return "success";
          }
      }


      注意:在使用`@RedisLimit`注解时,每个方法对应的key不应该相同,否则会出现相互干扰的情况。

      相关实践学习
      基于Redis实现在线游戏积分排行榜
      本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
      云数据库 Redis 版使用教程
      云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
      目录
      相关文章
      |
      1月前
      |
      XML Java 数据格式
      SpringBoot入门(8) - 开发中还有哪些常用注解
      SpringBoot入门(8) - 开发中还有哪些常用注解
      52 0
      |
      1天前
      |
      Java Spring
      【Spring】方法注解@Bean,配置类扫描路径
      @Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
      100 73
      |
      1天前
      |
      存储 Java Spring
      【Spring】获取Bean对象需要哪些注解
      @Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
      |
      17天前
      |
      NoSQL Java 关系型数据库
      Liunx部署java项目Tomcat、Redis、Mysql教程
      本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
      89 26
      |
      1天前
      |
      Java Spring
      【Spring配置】idea编码格式导致注解汉字无法保存
      问题一:对于同一个项目,我们在使用idea的过程中,使用汉字注解完后,再打开该项目,汉字变成乱码问题二:本来a项目中,汉字注解调试好了,没有乱码了,但是创建出来的新的项目,写的注解又成乱码了。
      |
      27天前
      |
      前端开发 Java Spring
      Spring MVC核心:深入理解@RequestMapping注解
      在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的核心,它将HTTP请求映射到控制器的处理方法上。本文将深入探讨`@RequestMapping`注解的各个方面,包括其注解的使用方法、如何与Spring MVC的其他组件协同工作,以及在实际开发中的应用案例。
      41 4
      |
      27天前
      |
      前端开发 Java 开发者
      Spring MVC中的请求映射:@RequestMapping注解深度解析
      在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
      103 2
      |
      27天前
      |
      前端开发 Java Spring
      探索Spring MVC:@Controller注解的全面解析
      在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
      46 2
      |
      1月前
      |
      消息中间件 Java 数据库
      解密Spring Boot:深入理解条件装配与条件注解
      Spring Boot中的条件装配与条件注解提供了强大的工具,使得应用程序可以根据不同的条件动态装配Bean,从而实现灵活的配置和管理。通过合理使用这些条件注解,开发者可以根据实际需求动态调整应用的行为,提升代码的可维护性和可扩展性。希望本文能够帮助你深入理解Spring Boot中的条件装配与条件注解,在实际开发中更好地应用这些功能。
      36 2
      |
      1月前
      |
      JSON Java 数据格式
      springboot常用注解
      @RestController :修饰类,该控制器会返回Json数据 @RequestMapping(“/path”) :修饰类,该控制器的请求路径 @Autowired : 修饰属性,按照类型进行依赖注入 @PathVariable : 修饰参数,将路径值映射到参数上 @ResponseBody :修饰方法,该方法会返回Json数据 @RequestBody(需要使用Post提交方式) :修饰参数,将Json数据封装到对应参数中 @Controller@Service@Compont: 将类注册到ioc容器