SpingBoot简单限流插件开发

SpingBoot简单限流插件开发

一、限流方案

   1、 Google的Guava工具包中就提供了一个限流工具类——RateLimiter,本文也是通过使用该工具类来实现限流功能。RateLimiter是基于“令牌通算法”来实现限流的。

   2、目前返回信息是 json 格式的数据,如果需要 xml ,可以将返回的类型放到 配置文件中,根据需要定制 

   3、本文只给出核心代码,详细代码,前往码云查看:https://gitee.com/wsy_13926404489/spring-boot-learning

二、限流器实现

   1、导入 jar 包

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>23.0</version>
</dependency>

 

   2、继承WebMvcConfigurerAdapter来添加自定义拦截器,主要实现  addInterceptors(InterceptorRegistry registry) 方法

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(limitInterceptor)
            .addPathPatterns("/**");
            //.excludePathPatterns()   不拦截路径
}

 

3、自定义拦截器,实现 HandlerInterceptor 接口,并在拦截器中实现限流

/**
 *  处理请求之前(保证业务系统的稳定)
 * @param request
 * @param response
 * @param handler
 * @return
 * @throws Exception
 */
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 统一设置字符编码 (中文、UTF-8)
    response.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
    response.setContentType("text/html; charset=UTF-8");
    // 限流
    boolean limit = limiter.tryAcquire();
    if(!limit){
        int code = Optional.ofNullable(limitProperties.getCode()).orElse(-1);
        String msg = Optional.ofNullable(limitProperties.getMsg()).orElse("服务繁忙,请稍后再试!");
        String result = "{\"msg\":\"" + msg + "\",\"code\":" + code +"}";
        response.getWriter().println(new String(result.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
        log.error("请求被拦截,返回消息:{}" , new String(result.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
        return false;
    }
    return true;
}

 

4、实例化 RateLimiter 对象,用于拦截

/**
 * 限流实例
 * @return
 */
@Bean
public RateLimiter getRateLimiter(@Autowired  ApplicationContext applicationContext){
    //判断是否存在 limit.count 存在获取该值,且该值必须大于 0 ,不存在将该值设置为 int 的最大值(即不限流)
    int limitCount = DEFAULT_LIMITCOUNT;
    String limitCountStr = applicationContext.getEnvironment().getProperty("limit.count");
    if(!StringUtils.isEmpty(limitCountStr) && !Objects.equals(limitCountStr.trim(), "0")){
        if(Integer.parseInt(limitCountStr.trim()) > 0){
            limitCount = Integer.parseInt(limitCountStr.trim());
        }
    }
    log.info("配置的最大QPS: {}", limitCount);
    return RateLimiter.create(limitCount);
}

 

5、将一些入参信息放到配置文件中,根据使用时需要

@Data
@ConfigurationProperties(prefix = "limit")
@Component
public class LimitProperties {

    // 每秒产生别的令牌数
    private Integer count;

    // 超时返回的消息(快速失败消息)
    private String msg;

    //返回给前端的编码()
    private Integer code;
}

 

三、在项目中使用

   1、引入组件的 jar 

<dependency>
   <groupId>org.example</groupId>
   <artifactId>limit-spring-boot-starter</artifactId>
   <version>1.0-SNAPSHOT</version>
</dependency>

 


   2、添加必要的参数配置

    limit.count # 最大 QPS
    limit.msg   # 超时后返回给调用者的消息说明 
    limit.code  # 超时返回调用者的响应码(不是 httpCode、不管请求是否拦截 httpCode 都是返回 200)

 

3、新建一个 controller ,简单的接口即可,如下:

@RestController
public class LimitCtrl {

    @GetMapping("/limit")
    public JSONObject limit(){
        JSONObject result = new JSONObject();
        result.put("code", 0);
        result.put("msg", "请求成功");
        return result;
    }
}

4、使用 JMeter 对测试接口进行压测,返回消息如下:

{"msg":"服务繁忙,请稍后再试!","code":1}

5、查看日志:

2021-05-24 14:38:42.440 ERROR 7976 --- [nio-8080-exec-7] c.w.limit.interceptor.LimitInterceptor   : 请求被拦截,返回消息:{"msg":"服务异常,请稍后再试!","code":1}

 

项目路径:https://gitee.com/wsy_13926404489/spring-boot-learning.git

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值