千家信息网

Java如何实现接口限流

发表于:2024-11-11 作者:千家信息网编辑
千家信息网最后更新 2024年11月11日,小编给大家分享一下Java如何实现接口限流,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!RateLimiterGoogle开源工具包Guava提供了限流工具类RateLimiter,
千家信息网最后更新 2024年11月11日Java如何实现接口限流

小编给大家分享一下Java如何实现接口限流,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

RateLimiter

Google开源工具包Guava提供了限流工具类RateLimiter,基于令牌桶算法实现。

1.maven依赖:

    com.google.guava    guava    27.1-jre

2.自定义注解

import java.lang.annotation.*;import java.util.concurrent.TimeUnit;/** * 令牌桶注解实现 */@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface RequestLimiter {    /**     * 每秒创建令牌个数,默认:10     */    double QPS() default 10D;    /**     * 获取令牌等待超时时间 默认:500     */    long timeout() default 500;    /**     * 超时时间单位 默认:毫秒     */    TimeUnit timeunit() default TimeUnit.MILLISECONDS;    /**     * 无法获取令牌返回提示信息     */    String msg() default "请稍后再试!";}

3.拦截器

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.google.common.util.concurrent.RateLimiter;import com.tiam.panshi.cloud.appback.annotation.RequestLimiter;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.PrintWriter;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;@Component@Slf4jpublic class RequestLimitingInterceptor implements HandlerInterceptor {    private final Map rateLimiterMap = new ConcurrentHashMap<>();    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {        //这里可以抽出去定义返回信息        JSONObject jsonObject = new JSONObject();        jsonObject.put("10001", "玩命加载中,请稍后再试");        try {            if (handler instanceof HandlerMethod) {                HandlerMethod handlerMethod = (HandlerMethod) handler;                RequestLimiter rateLimit = handlerMethod.getMethodAnnotation(RequestLimiter.class);                //判断是否有注解                if (rateLimit != null) {                    // 获取请求url                    String url = request.getRequestURI();                    RateLimiter rateLimiter;                    // 判断map集合中是否有创建好的令牌桶                    if (!rateLimiterMap.containsKey(url)) {                        // 创建令牌桶,以n r/s往桶中放入令牌                        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());                        makeResult(response, renderJson(jsonObject));                        return false;                    }                }            }            return true;        } catch (Exception var6) {            var6.printStackTrace();            makeResult(response, renderJson(jsonObject));            return false;        }    }    private void makeResult(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 renderJson(Object o) {        return JSONObject.parseObject(JSON.toJSONString(o));    }

4.注册拦截器

@Configurationpublic class WebMvcConfig extends WebMvcConfigurationSupport {     /**      * 请求限流拦截器      */     @Autowired     protected RequestLimitingInterceptor requestLimitingInterceptor;     @Override     public void addInterceptors(InterceptorRegistry registry) {         // 请求限流         registry.addInterceptor(requestLimitingInterceptor).addPathPatterns("/**");     }}

5.在接口上配置注解

@RequestLimiter(QPS = 5D, timeout = 200, timeunit = TimeUnit.MILLISECONDS,msg = "玩命加载中,请稍后再试")@GetMapping("/test")@ResponseBodypublic String test(){      return "";}

看完了这篇文章,相信你对"Java如何实现接口限流"有了一定的了解,如果想了解更多相关知识,欢迎关注行业资讯频道,感谢各位的阅读!

0