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 ""; }
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- SpringBoot利用限速器RateLimiter實現單機限流的示例代碼
- java實現單機限流
- Java 實現限流器處理Rest接口請求詳解流程
- 使用springboot整合RateLimiter限流過程
- SpringBoot如何使用RateLimiter通過AOP方式進行限流