最近有个网友问了一个问题,zuul中如果两个filter的order一样,是如何排序的?引起了我的趣味,特地去浏览了它的源码。
如果你有应用过springcloud应该据说过zuul,它的定位是散布式微服务中的API网关服务,当然前面可能要被gateway代替了。zuul是一个L7应用程序网关,提供了动静路由,监督,弹性,安全性等性能。zuul的大部分性能是通过filter实现的。
zuul定义了四种不同生命周期的filter
为了不便操作,zuul内置了一些filter,这些filter次要通过@EnableZuulServer
和@EnableZuulProxy
注解开启相干性能。@EnableZuulServer
注解开启的filter性能如下:
@EnableZuulProxy
注解除了开启下面这些filter性能之外,还开启了如下的性能:
只需继承ZuulFilter
类,实现它的filterType
、filterOrder
、shouldFilter
和 run
办法即可,具体实现可参考如下代码:
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);
该办法的具体逻辑
- 依据filterType从缓存中获取filter汇合,如果缓存中有间接返回
- 如果缓存中没有,则创立filter汇合,将所有filter中跟filterType的filter增加到filter汇合中。
- 排序filter汇合
- 将新创建的filter汇合放入缓存。
从下面能够看出filter的排序是通过如下办法执行的:
Collections.sort(list);
该办法底层其实是通过list
的sort
办法实现的
看看ArrayList
的sort
办法,传入的Comparator
为null
它的底层又是通过Arrays
类的静态方法sort
实现的
因为上一步Comparator
为null,则会执行sort
办法。
该办法是通过ComparableTimSort
类的sort
办法实现的,这个办法是最外围的办法了
咱们能够看到该办法其实是通过binarySort
二分查找排序的。
通过compareTo
办法比拟大小。
咱们回头再看看ZuulFilter
类
它实现了Comparable
接口,重写了compareTo
办法
所以,看到这里咱们能够得出结论:ZuulFilter
是通过Integer
的compare
办法比拟filterOrder
参数值大小来排序的。
咱们看看Integer
的compare
办法具体的逻辑!
如果x==y,则返回0,x<y,则返回 -1,否则返回1 后面在二分查找中,只有x<y时,才会替换地位。
看到这里,咱们得出这样的论断,如果filterOrder
一样,则Collections.sort(list);
排序时不替换地位,这依照ZuulFilter
默认加载程序。那么,ZuulFilter的默认加载程序是怎么样的?
它是通过getAllFilters
办法获取ZuulFilter
汇合,该办法其实返回的是名称为filters
的ConcurrentHashMap
的values
,即返回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
办法,该办法后面曾经介绍过了。
如果这篇文章对您有所帮忙,或者有所启发的话,帮忙扫描下发二维码关注一下,或者点赞、转发、在看。在公众号中回复:面试、代码神器、开发手册、工夫治理有超赞的粉丝福利,另外回复:加群,能够跟很多大厂的前辈交换和学习。