这是一个使用 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 来存储用户请求次数,可以有效地提高限流器的性能。

Java 注解实现限流方案:通过 Redis 控制用户请求频率

原文地址: https://www.cveoy.top/t/topic/lVrD 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录