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不应该相同,否则会出现相互干扰的情况。
推荐阅读
springboot 高级教程 如何优雅使用redission分布式锁
springboot 高级教程 全局异常处理
springboot mysql读写分离
什么是缓存穿透,如何避免
MySQL 百万级数据分页查询及优化
nginx配置负载均衡的服务宕机了,怎么配置高可用
加群交流