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 "";
}

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

相关文章

  • 基于编译虚拟机jvm—openjdk的编译详解

    基于编译虚拟机jvm—openjdk的编译详解

    下面小编就为大家分享一篇基于编译虚拟机jvm—openjdk的编译详解,具有很好的参考价值,希望对大家有所帮助
    2017-12-12
  • java把字符串写入文件里的简单方法分享

    java把字符串写入文件里的简单方法分享

    这篇文章主要介绍了java把字符串写入到文件里的简单方法,这是跟一个外国朋友学的代码,需要的朋友可以参考下
    2014-03-03
  • springsecurity记住我登录时访问无权限接口跳转登录界面的处理方案

    springsecurity记住我登录时访问无权限接口跳转登录界面的处理方案

    这篇文章主要介绍了springsecurity记住我登录时访问无权限接口跳转登录界面的处理方案,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-02-02
  • ClassLoader类加载源码解析

    ClassLoader类加载源码解析

    这篇文章主要为大家详细解析了ClassLoader类加载源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-09-09
  • java使用枚举封装错误码及错误信息详解

    java使用枚举封装错误码及错误信息详解

    这篇文章主要介绍了java使用枚举封装错误码及错误信息,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • SpringCloud OpenFeign基本介绍与实现示例

    SpringCloud OpenFeign基本介绍与实现示例

    OpenFeign源于Netflix的Feign,是http通信的客户端。屏蔽了网络通信的细节,直接面向接口的方式开发,让开发者感知不到网络通信细节。所有远程调用,都像调用本地方法一样完成
    2023-02-02
  • idea compile项目正常启动项目的时候build失败报“找不到符号”等问题及解决方案

    idea compile项目正常启动项目的时候build失败报“找不到符号”等问题及解决方案

    这篇文章主要介绍了idea compile项目正常,启动项目的时候build失败,报“找不到符号”等问题,这种问题属于lombok编译失败导致,可能原因是依赖jar包没有更新到最新版本,需要的朋友可以参考下
    2023-10-10
  • Java实现二分查找树及其相关操作

    Java实现二分查找树及其相关操作

    二分查找树是一种有组织的二叉树。我们可以通过链接节点表示这样一棵树,二分查找树(Binary Search Tree)的基本操作有搜索、求最大值、求最小值、求前驱、求后继、插入及删除,对java二分查找树相关知识感兴趣的朋友一起看看吧
    2021-07-07
  • shiro 与 SpringMVC的整合完美示例

    shiro 与 SpringMVC的整合完美示例

    shiro可以直接和spring整合,但是这样需要单独配置spring用于整合shiro,在配置springmvc,接下来通过实例代码给大家介绍shiro 整合 SpringMVC 的方法,感兴趣的朋友一起看看吧
    2021-08-08
  • 基于mybatis进行批量更新两种方法

    基于mybatis进行批量更新两种方法

    这篇文章主要给大家介绍了关于如何基于mybatis进行批量更新的两种方法,批量更新的使用,mybatis中批量更新有很多种方法,可以把数据一条条更新,也可以传入一个数据集一次性更新,需要的朋友可以参考下
    2023-08-08

最新评论