Java實(shí)現(xiàn)接口限流方案
本文實(shí)例為大家分享了Java實(shí)現(xiàn)接口限流方案的具體代碼,供大家參考,具體內(nèi)容如下
RateLimiter
Google開源工具包Guava提供了限流工具類RateLimiter,基于令牌桶算法實(shí)現(xiàn)。
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;
/**
* 令牌桶注解實(shí)現(xiàn)
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestLimiter {
/**
* 每秒創(chuàng)建令牌個(gè)數(shù),默認(rèn):10
*/
double QPS() default 10D;
/**
* 獲取令牌等待超時(shí)時(shí)間 默認(rèn):500
*/
long timeout() default 500;
/**
* 超時(shí)時(shí)間單位 默認(rèn):毫秒
*/
TimeUnit timeunit() default TimeUnit.MILLISECONDS;
/**
* 無法獲取令牌返回提示信息
*/
String msg() default "請(qǐng)稍后再試!";
}
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", "玩命加載中,請(qǐng)稍后再試");
try {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
RequestLimiter rateLimit = handlerMethod.getMethodAnnotation(RequestLimiter.class);
//判斷是否有注解
if (rateLimit != null) {
// 獲取請(qǐng)求url
String url = request.getRequestURI();
RateLimiter rateLimiter;
// 判斷map集合中是否有創(chuàng)建好的令牌桶
if (!rateLimiterMap.containsKey(url)) {
// 創(chuàng)建令牌桶,以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("請(qǐng)求被限流,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.注冊(cè)攔截器
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* 請(qǐng)求限流攔截器
*/
@Autowired
protected RequestLimitingInterceptor requestLimitingInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 請(qǐng)求限流
registry.addInterceptor(requestLimitingInterceptor).addPathPatterns("/**");
}
}
5.在接口上配置注解
@RequestLimiter(QPS = 5D, timeout = 200, timeunit = TimeUnit.MILLISECONDS,msg = "玩命加載中,請(qǐng)稍后再試")
@GetMapping("/test")
@ResponseBody
public String test(){
return "";
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot @PathVariable使用時(shí)遇到的問題及解決
這篇文章主要介紹了SpringBoot @PathVariable使用時(shí)遇到的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Spring動(dòng)態(tài)多數(shù)據(jù)源配置實(shí)例Demo
本篇文章主要介紹了Spring動(dòng)態(tài)多數(shù)據(jù)源配置實(shí)例Demo,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01
Java ThreadLocal的使用場(chǎng)景總結(jié)
ThreadLocal原本設(shè)計(jì)是為了解決并發(fā)時(shí),線程共享變量的問題,但由于過度設(shè)計(jì),從而導(dǎo)致它的理解難度大和使用成本高等問題。即便如此,ThreadLocal依舊有適合自己的使用場(chǎng)景,比如本文要介紹了這兩種使用場(chǎng)景,除了ThreadLocal之外,還真沒有合適的替代方案。2021-05-05
Spring?boot?CommandLineRunner啟動(dòng)任務(wù)傳參實(shí)例詳解
在使用SpringBoot構(gòu)建項(xiàng)目時(shí),我們通常有一些預(yù)先數(shù)據(jù)的加載,下面這篇文章主要給大家介紹了關(guān)于Spring?boot?CommandLineRunner啟動(dòng)任務(wù)傳參的相關(guān)資料,需要的朋友可以參考下2022-06-06
SSH框架網(wǎng)上商城項(xiàng)目第8戰(zhàn)之查詢和刪除商品類別功能實(shí)現(xiàn)
SSH框架網(wǎng)上商城項(xiàng)目第8戰(zhàn)之查詢和刪除商品類別功能實(shí)現(xiàn),為項(xiàng)目增加功能,添加、更新、刪除和查詢操作,感興趣的小伙伴們可以參考一下2016-05-05
SpringBoot配置線程池的實(shí)現(xiàn)示例
本文主要介紹了SpringBoot配置線程池的實(shí)現(xiàn)示例,主要包括在Spring Boot中創(chuàng)建和配置線程池,包括設(shè)置線程池的大小、隊(duì)列容量、線程名稱等參數(shù),感興趣的可以了解一下2023-09-09

