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@Componentpublic class RedisLimitAspect { @Autowiredprivate 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`注解:
@RestControllerpublic class TestController { @GetMapping("/test")@RedisLimit(key = "testKey", limit = 5, timeout = 60)public String test() {return "success";} }
注意:在使用`@RedisLimit`注解时,每个方法对应的key不应该相同,否则会出现相互干扰的情况。
加群交流