引言

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

zuul是干什么的

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

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

为了方便操作,zuul内置了一些filter,这些filter主要通过@EnableZuulServer@EnableZuulProxy注解开启相关功能。@EnableZuulServer注解开启的filter功能如下:

@EnableZuulProxy注解除了开启上面这些filter功能之外,还开启了如下的功能:

如何自定义filter

只需继承ZuulFilter类,实现它的filterTypefilterOrdershouldFilterrun方法即可,具体实现可参考如下代码:

public class LogFilter extends ZuulFilter {@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}@Overridepublic int filterOrder() {return 1;}@Overridepublic boolean shouldFilter() {return RequestContext.getCurrentContext().sendZuulResponse();}@Overridepublic Object run() throws ZuulException {RequestContext currentContext = RequestContext.getCurrentContext();HttpServletRequest request = currentContext.getRequest();log.info("zuul pre filter-->" + request.getRequestURL() + "-->" + request.getMethod());return null;}
}

上面的四个方法有哪些作用呢?

方法名称 作用
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>(){@Overridepublic 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方法,该方法前面已经介绍过了。

热门内容:
  • 服务被干爆了!竟然是日志的锅!!

  • 扔掉okhttp、httpClient,来试试这款轻量级HTTP客户端神器?

  • 刚入职,就被各种 Code Review,真的有必要吗?

  • 求你了,不要再在对外接口中使用枚举类型了!

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・。)ノ♡

zuul如果两个filter的order一样,是如何排序的?相关推荐

  1. mysql order by 多字段排序

    工作中需用到order by 后两个字段排序,但结果却产生了一个Bug,以此备录. [1]复现问题场景 为了说明问题,模拟示例数据库表students,效果同实例. 如下语句Sql_1: 1 SELE ...

  2. 迷你播放器--第一阶段(6)--添加搜索定位功能(进阶)-使用filter过滤以及对汉语拼音的排序匹配

    迷你播放器--第一阶段(6) 添加搜索定位功能(进阶)-使用filter过滤以及对汉语拼音的排序匹配; 本文章为CSDN作者原创,转载请保留出处:http://blog.csdn.net/lrs030 ...

  3. MYSQL数据库(十)- 数据表的插入(insert)、删(delete)、改(update)、查(select)、group by 分组、having语句设置分组条件,order by查询结果排序,

    目录结构 本章目录 一.插入insert: 方法一:insert标准插入数据写法 方法二:set插入数据写法 方法三:请看本章最后一个案例 二.插入update: 方法一:单表更新记录 方法二:多表更 ...

  4. 已有a,b两个链表,每个链表中的结点包括学号、成绩。要求把两个链表合并,按学号 升序排序

    /*已有a,b两个链表,每个链表中的结点包括学号.成绩.要求把两个链表合并,按学号 升序排序*/#include <stdio.h> #include <stdlib.h> t ...

  5. Mysql学习-group by with rollup 函数 和order by field()自定义排序函数

    今天看到同事的代码,学习到了 group by with rollup 函数 和order by field()自定义排序函数 group by with rollup 函数 文章地址 https:/ ...

  6. java 两个list排序_java实现两个不同list对象合并后并排序

    工作上遇到一个要求两个不同list对象合并后并排序 1.问题描述 从数据库中查询两张表的当天数据,并对这两张表的数据,进行合并,然后根据时间排序. 2.思路 从数据库中查询到的数据放到各自list中, ...

  7. java 类隔离_微服务架构中zuul的两种隔离机制实验

    ZuulException REJECTED_SEMAPHORE_EXECUTION 是一个最近在性能测试中经常遇到的异常.查询资料发现是因为zuul默认每个路由直接用信号量做隔离,并且默认值是100 ...

  8. FFMPEG中的两输入Filter实现(一)

    开帖大吉! 利用FFMPEG工作已有一年多,许多学习文档散落在电脑各处,没有一个清晰明确的组织脉络:还有踩过又填平的各种坑,时间久了难免遗忘,再次遭遇时仍然要从头查起:而且事必躬亲也是毫无疑问的低效率 ...

  9. 过滤器实现评论内容的限制,玫感字和字数,分别用两个Filter实现

    第一个filter package com.filter; import java.io.UnsupportedEncodingException; import javax.servlet.Filt ...

最新文章

  1. Unity中制作游戏的快照游戏支持玩家拍快照
  2. infomix数据库版本sql_数据库周刊31丨华为openGauss 正式开源;7月数据库排行榜发布...
  3. 7.组件连线(贝塞尔曲线)--从零起步实现基于Html5的WEB设计器Jquery插件(含源码)...
  4. C++经典面试题汇总
  5. pfsense 2.2RC版本应用
  6. 【Elasticsearch】Elasticsearch 最佳实践系列之分片恢复并发故障
  7. python中求2-1000的完数_C++求2→1000之间的完数。
  8. 微信原生支付 Native扫码支付( V3.3.7 版本)
  9. 云端软件平台 如何共享自己封装的云端软件
  10. Iphone8如何投屏到电脑 苹果手机投屏到电脑
  11. 不同时期的项目变更控制流程
  12. PR连接蓝牙后无声音
  13. SQL Server左连接
  14. Linux下使用云笔记及OneNote
  15. 2023年江苏省赛事网络空间安全理论题库
  16. 京东商城(360Buy)价格识别 java版
  17. C++ std::multiset返回值 has no member named ‘first’
  18. 报错:GET http://fonts.useso.com/css?family=Open+Sans:300,400,600,700amp;lang=en 0 () 处理
  19. PHP语法基础3.1
  20. Ubuntu Desktop 软件源

热门文章

  1. iOS项目的本地化处理(多国语言)
  2. 常见报错——Uncaught TypeError: document.getElementsByClassName(...).addEventListener is not a function...
  3. ASP.NET导出文件FileResult的使用
  4. 使用Apache cxf 和Spring在Tomcat下发布Webservice指南
  5. DB2 9 利用开辟(733 测验)认证指南,第 1 部分: 数据库工具与编程步调(6)
  6. 线性代数:第二章 矩阵及其运算
  7. 刻意练习:Python基础 -- Task12. 模块
  8. 【怎样写代码】小技巧 -- 关于引用类型的两种转换方式
  9. MSER 候选车牌区域检测
  10. 文件名有规则情况读取