乐趣区

关于spring-cloud:zuul如果两个filter的order一样是如何排序的

最近有个网友问了一个问题,zuul 中如果两个 filter 的 order 一样,是如何排序的?引起了我的趣味,特地去浏览了它的源码。

如果你有应用过 springcloud 应该据说过 zuul,它的定位是散布式微服务中的 API 网关服务,当然前面可能要被 gateway 代替了。zuul 是一个 L7 应用程序网关,提供了动静路由,监督,弹性,安全性等性能。zuul 的大部分性能是通过 filter 实现的。

zuul 定义了四种不同生命周期的 filter

为了不便操作,zuul 内置了一些 filter,这些 filter 次要通过 @EnableZuulServer@EnableZuulProxy注解开启相干性能。@EnableZuulServer注解开启的 filter 性能如下:

@EnableZuulProxy注解除了开启下面这些 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;
    }
}

下面的四个办法有哪些作用呢?

须要留神的是,要想使 zuul 的性能失效,切记要在 springboot 启动类 上定义 @EnableZuulServer@EnableZuulProxy注解,示意开启 zuul 的性能。

先看看所有的 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 参数值大小来排序的。

咱们看看 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 办法,该办法后面曾经介绍过了。

如果这篇文章对您有所帮忙,或者有所启发的话,帮忙扫描下发二维码关注一下,或者点赞、转发、在看。在公众号中回复:面试、代码神器、开发手册、工夫治理有超赞的粉丝福利,另外回复:加群,能够跟很多大厂的前辈交换和学习。

退出移动版