Java 注解实现限流方案:通过 Redis 控制用户请求频率
这是一个使用 Java 代码通过注解实现限流的完整方案,并解释了相关代码内容。
1. 定义注解
首先定义一个名为 RateLimit 的注解,用于指定用户 ID 和每秒最大请求次数:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimit {
int limit() default 5;
String key() default '';
}
这个注解有两个属性:
limit:每秒最大请求次数,默认为 5 次。key:用于区分不同用户的标识符,默认为空。
2. 实现注解处理器
接下来实现一个注解处理器 RateLimitInterceptor,用于处理被 @RateLimit 注解的方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Component
public class RateLimitInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate<String, Integer> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
RateLimit rateLimit = method.getAnnotation(RateLimit.class);
if (rateLimit != null) {
String key = rateLimit.key();
if (key.isEmpty()) {
key = request.getRemoteAddr();
}
int limit = rateLimit.limit();
Integer count = redisTemplate.opsForValue().get(key);
if (count == null) {
count = 1;
redisTemplate.opsForValue().set(key, count, 1, TimeUnit.SECONDS);
} else {
if (count < limit) {
count++;
redisTemplate.opsForValue().set(key, count, 1, TimeUnit.SECONDS);
} else {
response.setStatus(429);
return false;
}
}
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
这个处理器使用 Redis 记录每个用户在当前秒内的请求次数。如果请求次数超过了限制,就返回 429 状态码,表示请求过多。
3. 在 Spring 配置文件中注册处理器
最后,在 Spring 的配置文件中注册这个处理器:
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Autowired
private RateLimitInterceptor rateLimitInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(rateLimitInterceptor);
}
}
这样就完成了一个简单的限流器的实现。
使用示例
@RestController
public class MyController {
@GetMapping('/test')
@RateLimit(limit = 10, key = 'user_id')
public String test() {
return 'success';
}
}
在这个示例中,test 方法被 @RateLimit 注解修饰,指定了每秒最大请求次数为 10 次,并使用 user_id 作为用户标识符。这样,同一个用户在每秒内只能发送最多 10 次请求到 /test 接口。
总结
使用注解实现限流器可以方便地控制用户请求频率,避免服务器被短时间内的过多请求压垮。这个方案使用了 Redis 来存储用户请求次数,可以有效地提高限流器的性能。
原文地址: https://www.cveoy.top/t/topic/lVrD 著作权归作者所有。请勿转载和采集!