在上面Spring Security + Jwt 项目的搭建过程当中,我一直有一个问题。咱们假设咱们使用addFilterAt(A, B.class)。 即将A拦截器添加到B拦截器的位置。那么addFilterAt 既然没有覆盖原先的拦截器,那么A不是在B拦截器前面就是在B拦截器后面,那么岂不是和addFilterBefore 或者 addFilterAfter 重复了?java
然而元芳告诉我没那么简单。最下面有总结,不想看源码的小伙伴能够直接看总结。web
经过断点看到。咱们经过添加拦截器的代码是这个样子的。
那么咱们看源码:ide
为了更好的理解后面说的内容,咱们须要先了解一下 FilterComparator
这个类。顾名思义,这个类是一个过滤器比较器。能够看到以下
svg
其比较的规则以下, getOrder是根据类名来获取到过滤器的序号。能够看到过滤器的排序是根据排序序号的大小来排序的,序号小的在前,大的灾后。函数
public int compare(Filter lhs, Filter rhs) { Integer left = getOrder(lhs.getClass()); Integer right = getOrder(rhs.getClass()); return left - right; }
咱们这里拿 addFilterAt
举例,addFilterBefore
和 addFilterAfter
相似学习
一句一句看,先看第一句ui
this.comparator.registerAt(filter.getClass(), atFilter);
这里的 方法是 在 FilterComparator#registerAt
中
这里能够看到,当咱们使用addFilterAt 添加过滤器时,他添加的排序序号是和咱们指定的拦截器相同的。()this
public void registerAt(Class<? extends Filter> filter, Class<? extends Filter> atFilter) { // 获取 atFilter 的顺序 Integer position = getOrder(atFilter); if (position == null) { throw new IllegalArgumentException( "Cannot register after unregistered Filter " + atFilter); } // 将filter放入 filterToOrder 中, filterToOrder 是一个map集合 put(filter, position); } .... private void put(Class<? extends Filter> filter, int position) { String className = filter.getName(); filterToOrder.put(className, position); } // 调用 addFilterBefore 时使用这个方法注册,这里能够看到排序序号比指定过滤器要小1 public void registerBefore(Class<? extends Filter> filter, Class<? extends Filter> beforeFilter) { Integer position = getOrder(beforeFilter); if (position == null) { throw new IllegalArgumentException( "Cannot register after unregistered Filter " + beforeFilter); } put(filter, position - 1); } // 调用 addFilterAfter 时使用这个方法注册,这里能够看到排序序号比指定过滤器要大1 public void registerAfter(Class<? extends Filter> filter, Class<? extends Filter> afterFilter) { Integer position = getOrder(afterFilter); if (position == null) { throw new IllegalArgumentException( "Cannot register after unregistered Filter " + afterFilter); } put(filter, position + 1); }
简单来讲,就是咱们 添加的 jwtLoginFilter
拦截器和 UsernamePasswordAuthenticationFilter
的序号是相同的。spa
HttpSecurity#addFilter(Filter filter)
代码很简单,以下,将添加的过滤器加到 filters 集合中.net
public HttpSecurity addFilter(Filter filter) { Class<? extends Filter> filterClass = filter.getClass(); if (!comparator.isRegistered(filterClass)) { throw new IllegalArgumentException( "The Filter class " + filterClass.getName() + " does not have a registered order and cannot be added without a specified order. Consider using addFilterBefore or addFilterAfter instead."); } this.filters.add(filter); return this; }
经过断点咱们还能够发现,咱们手动添加的过滤器是先于大部分系统过滤器被加入到filters集合中的。这一点能够从断点中看到
另外从 HttpSecurity#performBuild
方法中咱们能够知道,filters 在添加完全部过滤器后,使用 FilterComparator
比较器进行了比较。结果呼之欲出。
FilterComparator
比较器中初始化了Spring Security 自带的Filter 的顺序,即在建立时已经肯定了默认Filter的顺序。并将全部过滤器保存在一个 filterToOrder
Map中。key值是Filter的类名,value是过滤器的顺序号。HttpSecurity#addFilterAt(A, B.class)
方法时(其中B必定是先于A添加,或者B自己就是默认的过滤器),他会将咱们的添加的过滤器A在 FilterComparator
,并给给咱们一个和B相同的序号(addFilterBefore(A, B.class) 给A的序号比B小1,addFilterAfter(A, B.class) 给A的序号比B大1)。同时,HttpSecurity#addFilter(Filter filter)
会将咱们添加的过滤器添加在 filters
List集合中, 而在List集合汇总咱们手动添加的拦截器在除了 WebAsyncManagerIntegrationFilter
以外的全部系统默认的拦截器以前。HttpSecurity#performBuild
方法,在这里会使用 FilterComparator
比较器对 filters
进行比较排序,序号小的在前,序号大的在后,序号相等则按照原先的filters中的顺序。filters
List集合中,咱们本身添加的过滤器要在除了 WebAsyncManagerIntegrationFilter
以外的全部系统默认的拦截器以前。致使了当咱们调用了 HttpSecurity#addFilterAt(A, B.class)
方法时,A拦截器要先于B拦截器执行。举例(为了好理解,纯属假设):
FilterComparator
构造函数中就有这三个拦截器的顺序值,假设Map值为{“AcName” : 100, “BcName” : 200, “CcName” : 300}。其中AcName是A拦截器的类名,BC同理,100,200,300是他们的序号,用于肯定顺序。FilterComparator
中注册F (保存在排序Map中),排序序号和B相同,也为 200,这时候Map 就变成了{“AcName” : 100, “BcName” : 200, “CcName” : 300, “FcName” : 200}。(若是调用addFilterBefore F的序号就会减1,变成199; 若是调用addFilterAfter F的序号就会加1,变成201)HttpSecurity
中也会把 F拦截器添加到一个待排序的List集合L中,而后在添加其余系统默认过滤器(至关于这个List保存了全部的过滤器,可是其调用顺序未肯定,还须要通过排序后才能肯定)。最终List集合L就变成了{ A, F, B, C} (以前写成了F,A,B,C了,经评论区指正,已修改),注意这个是未经排序的过滤器集合,排序后才是真正的调用顺序。HttpSecurity#performBuild
方法时,会将HttpSecurity
中的过滤器集合L进行排序,排序比较器就是FilterComparator
,排序规则就是谁的排序序号小谁在前,序号大的在后,序号相同的保持 L 中的顺序。而后,得出最后的过滤器顺序,也就是最终调用顺序。(讲的略乱,我已经尽力了。。。)
以上:内容部分木有参考 若有侵扰,联系删除。 内容仅用于自我记录学习使用。若有错误,欢迎指正