别小看Spring过滤器,这些知识点你必须得掌握!(上)

简介: 别小看Spring过滤器,这些知识点你必须得掌握!

容器启动时过滤器初始化以及排序注册相关逻辑。

1 @WebFilter过滤器使用@Order无效

启动程序:

image.png

Controller:

1.png

实现俩过滤器:

  • AuthFilter

1.png

  • TimeCostFilter

image.png

使用 @Order,期望 TimeCostFilter 先被执行,因为TimeCostFilter原本设计是统计这个接口性能,所以需要统计AuthFilter执行的授权过程。


全部代码实现完毕,执行结果如下:

image.png

观察日志,执行时间并不包含授权过程,所以这违背预期,明明加了 @Order呀!

但若交换Order指定的值,发现也没效果,why?Order不能排序WebFilter?

源码解析

当请求来时,会执行到 StandardWrapperValve#invoke(),创建 ApplicationFilterChain,并通过ApplicationFilterChain#doFilter() 触发过滤器执行,并最终执行到内部私有方法internalDoFilter(),尝试在internalDoFilter()中寻找一些启示:


image.png

image.png

可知,过滤器执行顺序由实例变量Filters维护,Filters是createFilterChain()在容器启动时顺序遍历StandardContext中的成员变量FilterMaps所获:

1.png

发现对 StandardContext#FilterMaps 的写入是在

addFilterMapBefore()

image.png

过滤器的执行顺序由StandardContext#FilterMaps顺序决定,而FilterMaps则是一个包装过的数组,所以只要进一步弄清FilterMaps中各元素的排列顺序即可。


addFilterMapBefore()中加入断点:

image.png

Spring从selfInitialize()一直调用到addFilterMapBefore()。

selfInitialize()通过调用getServletContextInitializerBeans()获取所有ServletContextInitializer类型Bean,并调用该Bean的onStartup(),最终调用到addFilterMapBefore()。


image.png

image.png

上述的selfInitialize()又从何处调用过来呢?

selfInitialize()

  • getServletContextInitializerBeans()
    返回的ServletContextInitializer类型Beans顺序=》
    决定了addFilterMapBefore()调用顺序=》
    决定FilterMaps内元素顺序=》
    最终决定了过滤器的执行顺序。

getServletContextInitializerBeans()

仅返回了ServletContextInitializerBeans类的一个实例,参考代码如下:

image.png

ServletContextInitializerBeans是个集合类

image.png

所以,selfInitialize()能遍历 ServletContextInitializerBeans,查看其iterator()所遍之物:

image.png

对外暴露的集合遍历元素为sortedList成员变量,即selfInitialize()最终遍历sortedList。

综上,sortedList中的过滤器Bean元素顺序决定最终过滤器的执行顺序。

继续查看ServletContextInitializerBeans构造器:

image.png

第87行可知:sortedList元素顺序由this.initializers.values通过AnnotationAwareOrderComparator排序而得。


AnnotationAwareOrderComparator通过两种方式获取比较器需要的order值以决定sortedInitializers的排列顺序:


  • 待排序的对象元素实现Order接口,则通过 getOrder() 获取order值
  • 否则执行 OrderUtils.findOrder() 获取该对象类 @Order 的属性


因为this.initializers.values类型为ServletContextInitializer,其实现了Ordered接口,所以此处比较器使用 getOrder() 获取order值,对应实例变量order


如下方法均构建了ServletContextInitializer子类的实例,并添加到了this.initializers


  • addAdaptableBeans()
  • addServletContextInitializerBeans()

这里只看addServletContextInitializerBeans,因为使用 @WebFilter 标记添加过滤器的方案最终只会通过该方法生效:实例化并注册了所有的ServletRegistrationBean、FilterRegistrationBean以及ServletListenerRegistrationBean。


在这个方法中,Spring通过 getOrderedBeansOfType() 实例化了所有ServletContextInitializer子类:

image.png

根据不同类型,调用addServletContextInitializerBean(),ServletContextInitializer子类包括:


  • ServletRegistrationBean
  • FilterRegistrationBean
  • ServletListenerRegistrationBean


正好对应了Servlet三大要素。

现在只关心对应Filter的FilterRegistrationBean,显然,FilterRegistrationBean是ServletContextInitializer的子类(实现了Ordered接口),同样由成员变量order的值决定其执行的优先级。

private void addServletContextInitializerBean(String beanName, ServletContextInitializer initializer,
      ListableBeanFactory beanFactory) {
      ...
   if (initializer instanceof FilterRegistrationBean) {
      Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
      addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
   }
   ...
}

最终添加到this.initializers

image.png

我们没有定义FilterRegistrationBean,那这里FilterRegistrationBean在哪里被定义出的?其order类成员变量是否有特定取值逻辑?

目录
相关文章
|
3月前
|
SQL Java 测试技术
在Spring boot中 使用JWT和过滤器实现登录认证
在Spring boot中 使用JWT和过滤器实现登录认证
202 0
|
22天前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
20 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
6月前
|
监控 Java 应用服务中间件
Spring Boot 源码面试知识点
【5月更文挑战第12天】Spring Boot 是一个强大且广泛使用的框架,旨在简化 Spring 应用程序的开发过程。深入了解 Spring Boot 的源码,有助于开发者更好地使用和定制这个框架。以下是一些关键的知识点:
91 6
|
2月前
|
Java 开发者 Spring
Spring Cloud Gateway 中,过滤器的分类有哪些?
Spring Cloud Gateway 中,过滤器的分类有哪些?
33 3
|
3月前
|
安全 搜索推荐 Java
|
3月前
|
前端开发 Java 开发者
|
3月前
|
安全 Java 开发者
|
3月前
|
安全 Java 测试技术
Spring Security 中的委托过滤器代理
【8月更文挑战第21天】
31 0
|
5月前
|
Java 开发者 Spring
Spring项目中Ordered接口的应用:全局过滤器(GlobalFilter)的顺序控制
Spring项目中Ordered接口的应用:全局过滤器(GlobalFilter)的顺序控制
207 2
|
5月前
|
Java API 数据安全/隐私保护
在Spring Boot中,过滤器(Filter)是一种非常有用的组件
在Spring Boot中,过滤器(Filter)是一种非常有用的组件
80 6