Created
August 26, 2017 04:21
-
-
Save ilaotan/a3301f30ccfcd95ccf1126bfa7bd3c9f to your computer and use it in GitHub Desktop.
springmvc限流
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.chen.utils.LoggerUtil; | |
import com.google.common.util.concurrent.RateLimiter; | |
import org.springframework.web.servlet.HandlerInterceptor; | |
import org.springframework.web.servlet.ModelAndView; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
public class SimpleRateLimitInterceptor implements HandlerInterceptor { | |
private RateLimiter globalRateLimiter; | |
public SimpleRateLimitInterceptor(int rate) { | |
if (rate > 0) | |
globalRateLimiter = RateLimiter.create(rate); | |
else | |
throw new RuntimeException("rate must greater than zero"); | |
} | |
public void setRate(int rate){ | |
globalRateLimiter.setRate(rate); | |
} | |
@Override | |
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | |
if (!globalRateLimiter.tryAcquire()) { | |
LoggerUtil.log(request.getRequestURI()+"请求超过限流器速率"); | |
return false; | |
} | |
return true; | |
} | |
@Override | |
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { | |
} | |
@Override | |
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { | |
} | |
} | |
import com.chen.limit.model.URLLimitMapping; | |
import com.chen.utils.LoggerUtil; | |
import com.google.common.base.Joiner; | |
import com.google.common.util.concurrent.RateLimiter; | |
import org.springframework.web.servlet.HandlerInterceptor; | |
import org.springframework.web.servlet.ModelAndView; | |
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition; | |
import org.springframework.web.util.UrlPathHelper; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Properties; | |
import java.util.concurrent.ConcurrentHashMap; | |
/** | |
* spring请求限流器 | |
* 可对全局请求或url表达式请求进行限流 | |
* 内部使用spring DispatcherServlet的匹配器PatternsRequestCondition | |
* 进行url的匹配。 | |
* | |
*/ | |
public class RateLimitInterceptor implements HandlerInterceptor { | |
private RateLimiter globalRateLimiter; | |
private Properties urlProperties; | |
private Map<PatternsRequestCondition, RateLimiter> urlRateMap; | |
private UrlPathHelper urlPathHelper; | |
private int globalRate; | |
private List<URLLimitMapping> limitMappings; | |
public RateLimitInterceptor() { | |
this(0); | |
} | |
/** | |
* @param globalRate 全局请求限制qps | |
*/ | |
public RateLimitInterceptor(int globalRate) { | |
urlPathHelper = new UrlPathHelper(); | |
this.globalRate = globalRate; | |
if (globalRate > 0) | |
globalRateLimiter = RateLimiter.create(globalRate); | |
} | |
/** | |
* @param globalRate 全局请求限制qps | |
*/ | |
public void setGlobalRate(int globalRate) { | |
this.globalRate = globalRate; | |
if (globalRate > 0) | |
globalRateLimiter = RateLimiter.create(globalRate); | |
} | |
/** | |
* url限流 | |
* | |
* @param urlProperties url表达式->qps propertis | |
*/ | |
public void setUrlProperties(Properties urlProperties) { | |
if (urlRateMap == null) | |
urlRateMap = new ConcurrentHashMap(); | |
fillRateMap(urlProperties, urlRateMap); | |
this.urlProperties = urlProperties; | |
} | |
/** | |
* url限流 | |
* | |
* @param limitMappings url表达式 array->qps mapping | |
*/ | |
public void setLimitMappings(List<URLLimitMapping> limitMappings) { | |
if (urlRateMap == null) | |
urlRateMap = new ConcurrentHashMap(); | |
fillRateMap(limitMappings, urlRateMap); | |
this.limitMappings = limitMappings; | |
} | |
/** | |
* 将url表达转换为PatternsRequestCondition,并生成对应RateLimiter | |
* 保存 | |
* | |
* @param controllerProperties | |
* @param map | |
*/ | |
private void fillRateMap(Properties controllerProperties, Map<PatternsRequestCondition, RateLimiter> map) { | |
if (controllerProperties != null) { | |
for (String key : controllerProperties.stringPropertyNames()) { | |
String value = controllerProperties.getProperty(key); | |
if (value.matches("[0-9]*[1-9][0-9]*")) { | |
map.put(new PatternsRequestCondition(key), RateLimiter.create(Double.valueOf(value))); | |
} else { | |
LoggerUtil.log(key + " 的值" + value + " 不是一个合法的限制"); | |
} | |
} | |
} | |
} | |
/** | |
* 将url表达转换为PatternsRequestCondition,并生成对应RateLimiter | |
* 保存 | |
* | |
* @param limitMappings | |
* @param map | |
*/ | |
private void fillRateMap(List<URLLimitMapping> limitMappings, Map<PatternsRequestCondition, RateLimiter> map) { | |
if (limitMappings != null) { | |
for (URLLimitMapping mapping : limitMappings) { | |
map.put(new PatternsRequestCondition(mapping.getUrls()), RateLimiter.create(Double.valueOf(mapping.getRate()))); | |
} | |
} | |
} | |
@Override | |
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { | |
if (urlRateMap != null) { | |
String lookupPath = urlPathHelper.getLookupPathForRequest(request); | |
for (PatternsRequestCondition patternsRequestCondition : urlRateMap.keySet()) { | |
//使用spring DispatcherServlet的匹配器PatternsRequestCondition进行匹配 | |
List<String> matches = patternsRequestCondition.getMatchingPatterns(lookupPath); | |
if (!matches.isEmpty()) { | |
if (urlRateMap.get(patternsRequestCondition).tryAcquire()) { | |
LoggerUtil.log(lookupPath + " 请求匹配到" + Joiner.on(",").join(patternsRequestCondition.getPatterns()) + "限流器"); | |
} else { | |
LoggerUtil.log(lookupPath + " 请求超过" + Joiner.on(",").join(patternsRequestCondition.getPatterns()) + "限流器速率"); | |
return false; | |
} | |
} | |
} | |
} | |
//全局限流 | |
if (globalRateLimiter != null) { | |
if (!globalRateLimiter.tryAcquire()) { | |
return false; | |
} | |
} | |
return true; | |
} | |
@Override | |
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { | |
} | |
@Override | |
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment