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不应该相同,否则会出现相互干扰的情况。