小编给大家分享一下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)@Documentedpublic @interface RequestLimiter { double QPS() default 10D; 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<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.注册拦截器
@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如何实现接口限流”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!