Java实现接口限流方案

 更新时间:2021年11月25日 15:31:54   作者:Lamantin  
这篇文章主要为大家详细介绍了Java实现接口限流方案,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Java实现接口限流方案的具体代码,供大家参考,具体内容如下

RateLimiter

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

1.maven依赖:

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

2.自定义注解

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * 令牌桶注解实现
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @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
@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("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.注册拦截器

@Configuration
public 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")
@ResponseBody
public String test(){
      return "";
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot @PathVariable使用时遇到的问题及解决

    SpringBoot @PathVariable使用时遇到的问题及解决

    这篇文章主要介绍了SpringBoot @PathVariable使用时遇到的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Spring动态多数据源配置实例Demo

    Spring动态多数据源配置实例Demo

    本篇文章主要介绍了Spring动态多数据源配置实例Demo,具有一定的参考价值,有兴趣的可以了解一下。
    2017-01-01
  • Java ThreadLocal的使用场景总结

    Java ThreadLocal的使用场景总结

    ThreadLocal原本设计是为了解决并发时,线程共享变量的问题,但由于过度设计,从而导致它的理解难度大和使用成本高等问题。即便如此,ThreadLocal依旧有适合自己的使用场景,比如本文要介绍了这两种使用场景,除了ThreadLocal之外,还真没有合适的替代方案。
    2021-05-05
  • Java之Spring注解开发案例详解

    Java之Spring注解开发案例详解

    这篇文章主要介绍了Java之Spring注解开发案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • springmvc视图解析流程代码实例

    springmvc视图解析流程代码实例

    这篇文章主要介绍了springmvc视图解析流程代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Spring boot CommandLineRunner启动任务传参实例详解

    Spring boot CommandLineRunner启动任务传参实例详解

    在使用SpringBoot构建项目时,我们通常有一些预先数据的加载,下面这篇文章主要给大家介绍了关于Spring boot CommandLineRunner启动任务传参的相关资料,需要的朋友可以参考下
    2022-06-06
  • SSH框架网上商城项目第8战之查询和删除商品类别功能实现

    SSH框架网上商城项目第8战之查询和删除商品类别功能实现

    SSH框架网上商城项目第8战之查询和删除商品类别功能实现,为项目增加功能,添加、更新、删除和查询操作,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • mybatis-plus 分页类型转换工具类

    mybatis-plus 分页类型转换工具类

    用mybatis-plus 的分页对象的时候,因为用mybatis-puls 查询出来的分页对象的records里的泛型是实体,有时候需要将实体转换为前端展示的对象,所有写了一个分页数据的类型转换工具,解决这个问题,对mybatis-plus 分页工具类相关知识感兴趣的朋友一起看看吧
    2022-03-03
  • SpringBoot配置线程池的实现示例

    SpringBoot配置线程池的实现示例

    本文主要介绍了SpringBoot配置线程池的实现示例,主要包括在Spring Boot中创建和配置线程池,包括设置线程池的大小、队列容量、线程名称等参数,感兴趣的可以了解一下
    2023-09-09
  • Java 蒙特卡洛算法求圆周率近似值实例详解

    Java 蒙特卡洛算法求圆周率近似值实例详解

    这篇文章主要介绍了蒙特卡洛算法的起源,特点,以及Java编程中利用蒙特卡洛算法计算圆周率近似值的实例,需要的朋友可以参考下
    2017-09-09

最新评论