基于Guava库的RateLimter实现注解控制接口速率限流(纯代码)

文章介绍了一个使用Java编写的限速注解和相应的拦截器实现,该拦截器基于Guava的RateLimiter来限制API接口的请求速率。当请求超出设定的QPS(每秒请求数)时,系统会返回错误提示并阻止进一步的请求,以防止系统过载。
摘要由CSDN通过智能技术生成
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
 
/**
 * 限速注解
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Limiter {
    /**
     * 每秒创建令牌个数,默认:200
     */
    double QPS() default 200;
 
    /**
     * 获取令牌等待超时时间 默认:500
     */
    long timeout() default 500;
 
    /**
     * 超时时间单位 默认:毫秒
     */
    TimeUnit timeunit() default TimeUnit.MILLISECONDS;
 
    /**
     * 限速提示信息
     */
    String msg() default "请稍后再试!";
}
import java.io.PrintWriter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.util.concurrent.RateLimiter;

import lombok.extern.slf4j.Slf4j;

/**
 * 限速拦截器
 */
@Component
@Slf4j
public class RequestLimitingInterceptor implements HandlerInterceptor {
    private final Map<String, RateLimiter> rateLimiterMap = new ConcurrentHashMap<>();
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        //定义返回信息
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "msg");
        try {
            if (handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                Limiter rateLimit = handlerMethod.getMethodAnnotation(Limiter.class);
                //判断是否有注解
                if (rateLimit != null) {
                    // 获取请求url
                    String url = request.getRequestURI();
                    RateLimiter rateLimiter;
                    // 判断map集合中是否有创建好的令牌桶
                    if (!rateLimiterMap.containsKey(url)) {
                        // 创建令牌桶
                        rateLimiter = RateLimiter.create(rateLimit.QPS());
                        rateLimiterMap.put(url, rateLimiter);
                    }
                    rateLimiter = rateLimiterMap.get(url);
                    // 获取令牌
                    boolean acquire = rateLimiter.tryAcquire(rateLimit.timeout(), rateLimit.timeunit());
                    if (acquire) {
                        //获取令牌成功
                        return true;
                    } else {
                        log.warn("请求被限流,url:{}", request.getServletPath());
                        response(response, toJsonObject(jsonObject));
                        return false;
                    }
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            response(response, toJsonObject(jsonObject));
            return false;
        }
    }
 
    private void response(HttpServletResponse response, JSONObject jo) {
        response.setContentType("application/json; charset=utf-8");
        response.setCharacterEncoding("UTF-8");
        // 语法糖,自动关闭流
        try (PrintWriter out = response.getWriter()) {
            out.append(jo.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    private JSONObject toJsonObject(Object o) {
        return JSONObject.parseObject(JSON.toJSONString(o));
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    /**
     * 请求限流拦截器
     */
    @Autowired
    protected RequestLimitingInterceptor requestLimitingInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 请求限流 根据后面的通配符路径拦截
        registry.addInterceptor(requestLimitingInterceptor).addPathPatterns("/**");
    }
}
@Limiter(QPS = 0.2, timeout = 100000, timeunit = TimeUnit.MILLISECONDS,msg = "玩命加载中,请稍后再试")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值