最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

springmvc限流攔截器的示例代碼

 更新時間:2017年12月01日 10:51:58   作者:valleychen1111  
本篇文章主要介紹了springmvc限流攔截器的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

限流器算法

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

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

漏桶算法

令牌桶算法

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

令牌桶算法工具RateLimiter

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

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

RateLimiter源碼分析

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

判斷是否可獲取令牌:

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

獲取令牌操作:

對于獲取令牌,根據(jù)nextFreeTicketMicros和當(dāng)前時間計算出新增的令牌數(shù),寫入當(dāng)前令牌桶令牌數(shù),重新計算nextFreeTicketMicros,桶內(nèi)還有令牌,則寫入當(dāng)前時間,并減少本次請求獲取的令牌數(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()) {
   //當(dāng)前時間
   long nowMicros = stopwatch.readMicros();
   //判斷是否可以在timeout時間內(nèi)獲取資源
   if (!canAcquire(nowMicros, timeoutMicros)) {
    return false;
   } else {
    //可獲取資源,對資源進(jìn)行重新計算,并返回當(dāng)前線程需要休眠時間
    microsToWait = reserveAndGetWaitLength(permits, nowMicros);
   }
  }
  //休眠
  stopwatch.sleepMicrosUninterruptibly(microsToWait);
  return true;
 }

判斷是否可獲取令牌:

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

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

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

final long reserveAndGetWaitLength(int permits, long nowMicros) {
  //獲取下次可獲取時間
  long momentAvailable = reserveEarliestAvailable(permits, nowMicros);
  //計算當(dāng)前線程需要休眠時間
  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中配置限流攔截器

  <mvc:interceptors>
    <!--限流攔截器-->
    <mvc:interceptor>
      <mvc:mapping path="/**"/>
      <bean class="limit.SimpleRateLimitInterceptor">
        <constructor-arg index="0" value="${totalRate}"/>
      </bean>
    </mvc:interceptor>
  </mvc:interceptors>

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

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

<mvc:interceptor>
      <mvc:mapping path="/**"/>

      <bean class="limit.RateLimitInterceptor">
        <!--單url限流-->
        <property name="urlProperties">
          <props>
            <prop key="/get/{id}">1</prop>
            <prop key="/post">2</prop>
          </props>
        </property>

      </bean>
</mvc:interceptor>

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

在攔截器preHandle方法中

//當(dāng)前請求路徑
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
//迭代所有url表達(dá)式對應(yīng)的PatternsRequestCondition
for (PatternsRequestCondition patternsRequestCondition : urlRateMap.keySet()) {
  //進(jìn)行匹配
  List<String> 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;
    }

  }
}

具體的實現(xiàn)類

請見github

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringCloud Gateway中斷言路由和過濾器的使用詳解

    SpringCloud Gateway中斷言路由和過濾器的使用詳解

    這篇文章主要介紹了SpringCloud Gateway中斷言路由和過濾器的使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Java使用DSA密鑰對生成XML簽名的方法

    Java使用DSA密鑰對生成XML簽名的方法

    這篇文章主要介紹了Java使用DSA密鑰對生成XML簽名的方法,實例分析了java使用DSA密鑰對生成XML簽名的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • Spring Boot中使用Spring-Retry重試框架的實現(xiàn)

    Spring Boot中使用Spring-Retry重試框架的實現(xiàn)

    本文主要介紹了Spring Boot中使用Spring-Retry重試框架的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Java抽象類和普通類區(qū)別、 數(shù)組跟List的區(qū)別解析

    Java抽象類和普通類區(qū)別、 數(shù)組跟List的區(qū)別解析

    這篇文章主要介紹了Java抽象類和普通類區(qū)別、 數(shù)組跟List的區(qū)別,在這里需要注意List是一個接口,不能直接實例化,需要使用具體的實現(xiàn)類來創(chuàng)建對象,本文結(jié)合示例代碼介紹的非常詳細(xì),需要的朋友參考下吧
    2023-09-09
  • Java 深入淺出講解泛型與包裝類

    Java 深入淺出講解泛型與包裝類

    泛型是在Java SE 1.5引入的的新特性,本質(zhì)是參數(shù)化類型,也就是說所操作的數(shù)據(jù)類型被指定為一個參數(shù)。這種參數(shù)類型可以用在類、接口和方法的創(chuàng)建中,分別稱為泛型類、泛型接口、泛型方法,本篇我們一起來學(xué)習(xí)泛型以及包裝類
    2022-04-04
  • Java中文件的操作與輸入輸出流舉例詳解

    Java中文件的操作與輸入輸出流舉例詳解

    Java語言的輸入輸出功能是十分強大而靈活的,下面這篇文章主要給大家介紹了關(guān)于Java中文件的操作與輸入輸出流的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • Java Spring之@Async原理案例詳解

    Java Spring之@Async原理案例詳解

    這篇文章主要介紹了Java Spring之@Async原理案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-09-09
  • Mybatis批量插入并返回主鍵id的方法

    Mybatis批量插入并返回主鍵id的方法

    本文主要介紹了Mybatis批量插入并返回主鍵id的方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • mybatis中mapper.xml文件的常用屬性及標(biāo)簽講解

    mybatis中mapper.xml文件的常用屬性及標(biāo)簽講解

    這篇文章主要介紹了mybatis中mapper.xml文件的常用屬性及標(biāo)簽講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java計算值所占的百分比,結(jié)果為100%問題

    java計算值所占的百分比,結(jié)果為100%問題

    這篇文章主要介紹了java計算值所占的百分比,結(jié)果為100%問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評論

永兴县| 奉贤区| 和田县| 永顺县| 无极县| 博湖县| 健康| 吉林省| 开封县| 雷山县| 阿瓦提县| 石泉县| 淳化县| 仁布县| 诏安县| 湛江市| 醴陵市| 津南区| 黔东| 屏边| 蒲江县| 德兴市| 米泉市| 钟祥市| 任丘市| 喀什市| 通许县| 波密县| 定陶县| 满城县| 灵山县| 万源市| 广德县| 阜平县| 漳浦县| 德格县| 嵊州市| 兴业县| 迁安市| 鹿泉市| 晋州市|