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

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
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
      目录
      相关文章
      |
      3月前
      |
      XML Java 数据格式
      SpringBoot入门(8) - 开发中还有哪些常用注解
      SpringBoot入门(8) - 开发中还有哪些常用注解
      73 0
      |
      17天前
      |
      缓存 Java 数据库
      SpringBoot缓存注解使用
      Spring Boot 提供了一套方便的缓存注解,用于简化缓存管理。通过 `@Cacheable`、`@CachePut`、`@CacheEvict` 和 `@Caching` 等注解,开发者可以轻松地实现方法级别的缓存操作,从而提升应用的性能和响应速度。合理使用这些注解可以大大减少数据库的访问频率,优化系统性能。
      162 89
      |
      4天前
      |
      监控 Java Spring
      SpringBoot:SpringBoot通过注解监测Controller接口
      本文详细介绍了如何通过Spring Boot注解监测Controller接口,包括自定义注解、AOP切面的创建和使用以及具体的示例代码。通过这种方式,可以方便地在Controller方法执行前后添加日志记录、性能监控和异常处理逻辑,而无需修改方法本身的代码。这种方法不仅提高了代码的可维护性,还增强了系统的监控能力。希望本文能帮助您更好地理解和应用Spring Boot中的注解监测技术。
      33 16
      |
      29天前
      基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
      基于springboot+thymeleaf+Redis仿知乎网站问答项目源码
      129 36
      |
      1月前
      |
      NoSQL 算法 Java
      Java Redis多限流
      通过本文的介绍,我们详细讲解了如何在Java中使用Redis实现三种不同的限流策略:固定窗口限流、滑动窗口限流和令牌桶算法。每种限流策略都有其适用的场景和特点,根据具体需求选择合适的限流策略可以有效保护系统资源和提高服务的稳定性。
      60 18
      |
      2月前
      |
      NoSQL Java 关系型数据库
      Liunx部署java项目Tomcat、Redis、Mysql教程
      本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
      181 26
      |
      3月前
      |
      消息中间件 Java 数据库
      解密Spring Boot:深入理解条件装配与条件注解
      Spring Boot中的条件装配与条件注解提供了强大的工具,使得应用程序可以根据不同的条件动态装配Bean,从而实现灵活的配置和管理。通过合理使用这些条件注解,开发者可以根据实际需求动态调整应用的行为,提升代码的可维护性和可扩展性。希望本文能够帮助你深入理解Spring Boot中的条件装配与条件注解,在实际开发中更好地应用这些功能。
      61 2
      |
      3月前
      |
      XML Java 数据格式
      SpringBoot入门(8) - 开发中还有哪些常用注解
      SpringBoot入门(8) - 开发中还有哪些常用注解
      61 2
      |
      3月前
      |
      NoSQL Java API
      springboot项目Redis统计在线用户
      通过本文的介绍,您可以在Spring Boot项目中使用Redis实现在线用户统计。通过合理配置Redis和实现用户登录、注销及统计逻辑,您可以高效地管理在线用户。希望本文的详细解释和代码示例能帮助您在实际项目中成功应用这一技术。
      97 4
      |
      3月前
      |
      消息中间件 NoSQL Java
      Spring Boot整合Redis
      通过Spring Boot整合Redis,可以显著提升应用的性能和响应速度。在本文中,我们详细介绍了如何配置和使用Redis,包括基本的CRUD操作和具有过期时间的值设置方法。希望本文能帮助你在实际项目中高效地整合和使用Redis。
      116 2