引言

最近有个网友问了一个问题,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. 我哭了,工业界AI项目落地有多难?
  2. 在matlab中清除command history中的内容
  3. Java XML解析器
  4. Servlet之Filter过滤器
  5. 文件上传测试 bugku
  6. 万亿条数据查询如何做到毫秒级响应?
  7. 【Floyed】【最短路】商店选址问题(ssl 1760)
  8. Spring,REST,Ajax和CORS
  9. IIS AppCreate子目录的错误(0x80020006)
  10. esc centos 安装mysql_CentOS7安装Mysql
  11. centos 指定文件路径 脚本_centos自动删除三天前文件的脚本和自动进入指定目录运行命令...
  12. 微信小程序源码:淘宝客外卖返利优惠券、头像 壁纸 朋友圈文案查询、古诗词技术文章查询
  13. 大二学生web期末大作业 在线电影网站 HTML+CSS+JS
  14. Ubuntu18安装AWVS,然后在破姐次数限制,就问你能不能忍住不赞?
  15. 房屋租赁合同模板2020 免费下载
  16. css样式背景图片设置透明度,css如何设置背景图片的透明度
  17. 视频编码-码率控制CQP/CRF/ABR/CBR/VBV
  18. RoadMap:面向自动驾驶视觉定位的轻量级语义地图(ICRA2021)
  19. 关于投资有哪些不得不读的书籍?
  20. 数据库系统概论--第六章 关系数据理论

热门文章

  1. 余额宝技术架构读后感
  2. React和vue的差异和相似地方
  3. 【Java】身份证号码验证
  4. Install Package and Software
  5. COJ 0995 WZJ的数据结构(负五)区间操作
  6. 控件包含代码块,因此无法修改控件集合
  7. 【怎样写代码】复杂对象的组装与创建 -- 建造者模式(五):关于Director的进一步讨论
  8. 【MATLAB】符号数学计算(八):符号分析可视化
  9. android system window,Android控件的fitSystemWindows属性
  10. 被Python「苦虐」的日子太惨了!