Java实现接口限流方案

2022-06-25 08:35:15

RateLimiter

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

1.maven依赖:

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>27.1-jre</version></dependency>

2.自定义注解

importjava.lang.annotation.*;importjava.util.concurrent.TimeUnit;/**
 * 令牌桶注解实现
 */@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic@interfaceRequestLimiter{/**
     * 每秒创建令牌个数,默认:10
     */doubleQPS()default10D;/**
     * 获取令牌等待超时时间 默认:500
     */longtimeout()default500;/**
     * 超时时间单位 默认:毫秒
     */TimeUnittimeunit()defaultTimeUnit.MILLISECONDS;/**
     * 无法获取令牌返回提示信息
     */Stringmsg()default"请稍后再试!";}

3.拦截器

importcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.JSONObject;importcom.google.common.util.concurrent.RateLimiter;importcom.tiam.panshi.cloud.appback.annotation.RequestLimiter;importlombok.extern.slf4j.Slf4j;importorg.springframework.stereotype.Component;importorg.springframework.web.method.HandlerMethod;importorg.springframework.web.servlet.HandlerInterceptor;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.PrintWriter;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;@Component@Slf4jpublicclassRequestLimitingInterceptorimplementsHandlerInterceptor{privatefinalMap<String,RateLimiter> rateLimiterMap=newConcurrentHashMap<>();@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler){//这里可以抽出去定义返回信息JSONObject jsonObject=newJSONObject();
        jsonObject.put("10001","玩命加载中,请稍后再试");try{if(handlerinstanceofHandlerMethod){HandlerMethod handlerMethod=(HandlerMethod) handler;RequestLimiter rateLimit= handlerMethod.getMethodAnnotation(RequestLimiter.class);//判断是否有注解if(rateLimit!=null){// 获取请求urlString 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){//获取令牌成功returntrue;}else{
                        log.warn("请求被限流,url:{}", request.getServletPath());makeResult(response,renderJson(jsonObject));returnfalse;}}}returntrue;}catch(Exception var6){
            var6.printStackTrace();makeResult(response,renderJson(jsonObject));returnfalse;}}privatevoidmakeResult(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();}}privateJSONObjectrenderJson(Object o){returnJSONObject.parseObject(JSON.toJSONString(o));}

4.注册拦截器

@ConfigurationpublicclassWebMvcConfigextendsWebMvcConfigurationSupport{/**
      * 请求限流拦截器
      */@AutowiredprotectedRequestLimitingInterceptor requestLimitingInterceptor;@OverridepublicvoidaddInterceptors(InterceptorRegistry registry){// 请求限流
         registry.addInterceptor(requestLimitingInterceptor).addPathPatterns("/**");}}

5.在接口上配置注解

@RequestLimiter(QPS=5D, timeout=200, timeunit=TimeUnit.MILLISECONDS,msg="玩命加载中,请稍后再试")@GetMapping("/test")@ResponseBodypublicStringtest(){return"";}
  • 作者:Lamantin
  • 原文链接:https://blog.csdn.net/JST888_K/article/details/121522459
    更新时间:2022-06-25 08:35:15