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

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

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

image.png

zuul定義了四種不一樣生命週期的filterspring

image.png

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

image.png

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

image.png

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

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;
    }
}

上面的四個方法有哪些做用呢?分佈式

image.png

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

先看看全部的zuulFilter在哪裏執行的,謎底就在FilterProcessor類的runFilters方法中。微服務

image.png

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

咱們重點看看這個方法

FilterLoader.getInstance().getFiltersByType(sType);

該方法的具體邏輯
image.png

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

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

Collections.sort(list);

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

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

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

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

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

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

image.png
經過compareTo方法比較大小。

咱們回頭再看看ZuulFilter

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

image.png

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

咱們看看Integercompare方法具體的邏輯!
image.png

若是x==y,則返回0,x<y,則返回 -1,不然返回1 前面在二分查找中,只有x<y時,纔會交換位置。
image.png

看到這裏,咱們得出這樣的結論,若是filterOrder同樣,則Collections.sort(list);排序時不交換位置,這按照ZuulFilter默認加載順序。那麼,ZuulFilter的默認加載順序是怎麼樣的?
image.png

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

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

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

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

  • 實現Comparable接口,重寫compareTo方法,
  • 實現Comparator接口,重寫compare方法

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

image.png

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

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

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

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

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

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

image.png
默認狀況下,若是不指定value值,則value是Integer的最大值。因爲排序規則是value越小,則排在越靠前,因此若是不指定value值,則它排在最後。
image.png
spring是經過OrderComparator類排序的,它實現了Comparator接口,它的doCompare方法實現的排序。

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

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

相關文章
相關標籤/搜索