zuul若是兩個filter的order同樣,是如何排序的?

引言

最近有個網友問了一個問題,zuul中若是兩個filter的order同樣,是如何排序的?引發了個人興趣,特意去閱讀了它的源碼。java

zuul是幹什麼的

若是你有使用過springcloud應該據說過zuul,它的定位是分佈式微服務中的API網關服務,固然後面可能要被gateway替代了。zuul是一個L7應用程序網關,提供了動態路由,監視,彈性,安全性等功能。zuul的大部分功能是經過filter實現的。web

zuul定義了四種不一樣生命週期的filter面試

爲了方便操做,zuul內置了一些filter,這些filter主要經過@EnableZuulServer@EnableZuulProxy註解開啓相關功能。@EnableZuulServer註解開啓的filter功能以下:spring

@EnableZuulProxy註解除了開啓上面這些filter功能以外,還開啓了以下的功能:緩存

如何自定義filter

只需繼承ZuulFilter類,實現它的filterTypefilterOrdershouldFilterrun方法便可,具體實現可參考以下代碼:安全

public class LogFilter extends ZuulFilter {

@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}

@Override
public int filterOrder() {
return 1;
}

@Override
public boolean shouldFilter() {
return RequestContext.getCurrentContext().sendZuulResponse();
}

@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
log.info("zuul pre filter-->" + request.getRequestURL() + "-->" + request.getMethod());
return null;
}
}

上面的四個方法有哪些做用呢?springboot

方法名稱 做用
filterType filter類型,包含:pre、routing、post和error四種類型
filterOrder 排序,該值越小,filter越早執行
shouldFilter 開關,表示是否須要執行該filter
run filter具體的功能方法

須要注意的是,要想使zuul的功能生效,切記要在springboot啓動類上定義@EnableZuulServer@EnableZuulProxy註解,表示開啓zuul的功能。微信

filterOrder是如何排序的

先看看全部的zuulFilter在哪裏執行的,謎底就在FilterProcessor類的runFilters方法中。編輯器

該方法很簡單,先獲取全部zuulFilter,而後遍歷全部zuulFilter,調用processZuulFilter方法執行具體的zuulFilter,而後將執行結果返回。分佈式

咱們重點看看這個方法

FilterLoader.getInstance().getFiltersByType(sType);

該方法的具體邏輯

  1. 根據filterType從緩存中獲取filter集合,若是緩存中有直接返回
  2. 若是緩存中沒有,則建立filter集合,將全部filter中跟filterType的filter添加到filter集合中。
  3. 排序filter集合
  4. 將新建立的filter集合放入緩存。

從上面能夠看出filter的排序是經過以下方法執行的:

Collections.sort(list);

該方法底層實際上是經過listsort方法實現的

看看ArrayListsort方法,傳入的Comparator爲null

它的底層又是經過Arrays類的靜態方法sort實現的

因爲上一步Comparator爲null,則會執行sort方法。

該方法是經過ComparableTimSort類的sort方法實現的,這個方法是最核心的方法了

咱們能夠看到該方法實際上是經過binarySort二分查找排序的。

經過compareTo方法比較大小。

咱們回頭再看看ZuulFilter

它實現了Comparable接口,重寫了compareTo方法

因此,看到這裏咱們能夠得出結論:ZuulFilter是經過Integercompare方法比較filterOrder參數值大小來排序的。

若是filterOrder同樣如何排序?

咱們看看Integercompare方法具體的邏輯

若是x==y,則返回0,x<y,則返回 -1,不然返回1 前面在二分查找中,只有x<y時,纔會交換位置。看到這裏,咱們得出這樣的結論,若是filterOrder同樣,則Collections.sort(list);排序時不交換位置,這按照ZuulFilter默認加載順序。那麼,ZuulFilter的默認加載順序是怎麼樣的?

它是經過getAllFilters方法獲取ZuulFilter集合,該方法其實返回的是名稱爲filtersConcurrentHashMapvalues,即返回Set集合,是無序的。

  • 重要的事情說三遍:若是filterOrder同樣,ZuulFilter是無序的。
  • 重要的事情說三遍:若是filterOrder同樣,ZuulFilter是無序的。
  • 重要的事情說三遍:若是filterOrder同樣,ZuulFilter是無序的。

因此,filterOrder切記不要定義相同的,否則可能會出現沒法預知的執行結果。

兩種排序方法

自定義排序其實有兩種方法:

  • 實現Comparable接口,重寫compareTo方法,
  • 實現Comparator接口,重寫compare方法
    若是要使用 Collections.sort(list);排序,它默認用的是第一種方法,上面的 filterOrder之因此能夠排序,是由於 Integer實現了 Comparable接口,重寫了 compareTo方法

若是想本身定義排序規則能夠經過實現Comparator接口,重寫compare方法。

Collections.sort(list,new Comparator<Integer>(){
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});

它的底層也是經過二分查找實現的

那麼這兩種方法有什麼區別呢?

  • Comparable接口位於java.lang包下,而Comparator接口位於java.util包下。
  • Comparable接口是內部比較器,一個類若是想要使用Collections.sort(list) 方法進行排序,則須要實現該接口
  • Comparator接口是外部比較器用於對那些沒有實現Comparable接口或者對已經實現的Comparable中的排序規則不滿意進行排序.無需改變類的結構,更加靈活。

彩蛋

zuul中是經過filterOrder參數的大小排序的,而在spring中是經過@Order註解排序的。

默認狀況下,若是不指定value值,則value是Integer的最大值。因爲排序規則是value越小,則排在越靠前,因此若是不指定value值,則它排在最後。

spring是經過OrderComparator類排序的,它實現了Comparator接口,它的doCompare方法實現的排序。

最終也是調用Integer類的compare方法,該方法前面已經介紹過了。

若是這篇文章對您有所幫助,或者有所啓發的話,幫忙掃描下發二維碼關注一下,或者點贊、轉發、在看。在公衆號中回覆:面試、代碼神器、開發手冊、時間管理有超讚的粉絲福利,另外回覆:加羣,能夠跟不少大廠的前輩交流和學習。


本文分享自微信公衆號 - 蘇三說技術(gh_9f551dfec941)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索