真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

使用springmvc怎么實現(xiàn)一個限流攔截器

這期內(nèi)容當中小編將會給大家?guī)碛嘘P(guān)使用springmvc怎么實現(xiàn)一個限流攔截器,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

創(chuàng)新互聯(lián)建站-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比浙江網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式浙江網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋浙江地區(qū)。費用合理售后完善,十多年實體公司更值得信賴。

限流器算法

目前常用限流器算法為兩種:令牌桶算法和漏桶算法,主要區(qū)別在于:漏桶算法能夠強行限制請求速率,平滑突發(fā)請求,而令牌桶算法在限定平均速率的情況下,允許一定量的突發(fā)請求

下面是從網(wǎng)上找到的兩張算法圖示,就很容易區(qū)分這兩種算法的特性了

漏桶算法使用springmvc怎么實現(xiàn)一個限流攔截器

令牌桶算法使用springmvc怎么實現(xiàn)一個限流攔截器

針對接口來說,一般會允許處理一定量突發(fā)請求,只要求限制平均速率,所以令牌桶算法更加常見。

令牌桶算法工具RateLimiter

目前本人常用的令牌桶算法實現(xiàn)類當屬google guava的RateLimiter,guava不僅實現(xiàn)了令牌桶算法,還有緩存、新的集合類、并發(fā)工具類、字符串處理類等等。是一個強大的工具集

RateLimiter api可以查看并發(fā)編程網(wǎng)guava RateLimiter的介紹

RateLimiter源碼分析

RateLimiter默認情況下,最核心的屬性有兩個nextFreeTicketMicros,下次可獲取令牌時間,storedPermits桶內(nèi)令牌數(shù)。

判斷是否可獲取令牌:

每次獲取令牌的時候,根據(jù)桶內(nèi)令牌數(shù)計算最快下次能獲取令牌的時間nextFreeTicketMicros,判斷是否可以獲取資源時,只要比較nextFreeTicketMicros和當前時間就可以了,so easy

獲取令牌操作:

對于獲取令牌,根據(jù)nextFreeTicketMicros和當前時間計算出新增的令牌數(shù),寫入當前令牌桶令牌數(shù),重新計算nextFreeTicketMicros,桶內(nèi)還有令牌,則寫入當前時間,并減少本次請求獲取的令牌數(shù)。

如同java的AQS類一樣,RateLimiter的核心在tryAcquire方法

 public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
  //嘗試獲取資源最多等待時間
  long timeoutMicros = max(unit.toMicros(timeout), 0);
  //檢查獲取資源數(shù)目是否正確
  checkPermits(permits);
  long microsToWait;
  //加鎖
  synchronized (mutex()) {
   //當前時間
   long nowMicros = stopwatch.readMicros();
   //判斷是否可以在timeout時間內(nèi)獲取資源
   if (!canAcquire(nowMicros, timeoutMicros)) {
    return false;
   } else {
    //可獲取資源,對資源進行重新計算,并返回當前線程需要休眠時間
    microsToWait = reserveAndGetWaitLength(permits, nowMicros);
   }
  }
  //休眠
  stopwatch.sleepMicrosUninterruptibly(microsToWait);
  return true;
 }

判斷是否可獲取令牌:

 private boolean canAcquire(long nowMicros, long timeoutMicros) {
  //最早可獲取資源時間-等待時間<=當前時間 方可獲取資源
  return queryEarliestAvailable(nowMicros) - timeoutMicros <= nowMicros;
}

RateLimiter默認實現(xiàn)類的queryEarliestAvailable是取成員變量nextFreeTicketMicros

獲取令牌并計算需要等待時間操作:

final long reserveAndGetWaitLength(int permits, long nowMicros) {
  //獲取下次可獲取時間
  long momentAvailable = reserveEarliestAvailable(permits, nowMicros);
  //計算當前線程需要休眠時間
  return max(momentAvailable - nowMicros, 0);
}
 final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
  //重新計算桶內(nèi)令牌數(shù)storedPermits
  resync(nowMicros);
  long returnValue = nextFreeTicketMicros;
  //本次消耗的令牌數(shù)
  double storedPermitsToSpend = min(requiredPermits, this.storedPermits);
  //重新計算下次可獲取時間nextFreeTicketMicros
  double freshPermits = requiredPermits - storedPermitsToSpend;
  long waitMicros =
    storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
      + (long) (freshPermits * stableIntervalMicros);

  this.nextFreeTicketMicros = LongMath.saturatedAdd(nextFreeTicketMicros, waitMicros);
  //減少桶內(nèi)令牌數(shù)
  this.storedPermits -= storedPermitsToSpend;
  return returnValue;
 }

實現(xiàn)簡單的spring mvc限流攔截器

實現(xiàn)一個HandlerInterceptor,在構(gòu)造方法中創(chuàng)建一個RateLimiter限流器

public SimpleRateLimitInterceptor(int rate) {
    if (rate > 0)
      globalRateLimiter = RateLimiter.create(rate);
    else
      throw new RuntimeException("rate must greater than zero");
}

在preHandle調(diào)用限流器的tryAcquire方法,判斷是否已經(jīng)超過限制速率

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
   if (!globalRateLimiter.tryAcquire()) {
     LoggerUtil.log(request.getRequestURI()+"請求超過限流器速率");
     return false;
   }
   return true;
 }

在dispatcher-servlet.xml中配置限流攔截器

  
    
    
      
      
        
      
    
  

復(fù)雜版本的spring mvc限流攔截器

使用Properties傳入攔截的url表達式->速率rate


      

      
        
        
          
            1
            2
          
        

      

為每個url表達式創(chuàng)建一個對應(yīng)的RateLimiter限流器。url表達式則封裝為org.springframework.web.servlet.mvc.condition.PatternsRequestCondition。PatternsRequestCondition是springmvc 的DispatcherServlet中用來匹配請求和Controller的類,可以判斷請求是否符合這些url表達式。

在攔截器preHandle方法中

//當前請求路徑
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
//迭代所有url表達式對應(yīng)的PatternsRequestCondition
for (PatternsRequestCondition patternsRequestCondition : urlRateMap.keySet()) {
  //進行匹配
  List matches = patternsRequestCondition.getMatchingPatterns(lookupPath);
  if (!matches.isEmpty()) {
    //匹配成功的則獲取對應(yīng)限流器的令牌
    if (urlRateMap.get(patternsRequestCondition).tryAcquire()) {
      LoggerUtil.log(lookupPath + " 請求匹配到" + Joiner.on(",").join(patternsRequestCondition.getPatterns()) + "限流器");
    } else {
      //獲取令牌失敗
      LoggerUtil.log(lookupPath + " 請求超過" + Joiner.on(",").join(patternsRequestCondition.getPatterns()) + "限流器速率");
      return false;
    }

  }
}

上述就是小編為大家分享的使用springmvc怎么實現(xiàn)一個限流攔截器了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


當前文章:使用springmvc怎么實現(xiàn)一個限流攔截器
網(wǎng)頁網(wǎng)址:http://weahome.cn/article/jjddjo.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部