Spring-web源码解析之Filter-OncePerRequestFilter:

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 基于4.1.7.RELEASE我们先看一个filter-mapping的配置  encodingFilter /* REQUEST ASYNC这里指定了...

基于4.1.7.RELEASE


我们先看一个filter-mapping的配置 

<filter-mapping>
   <filter-name>encodingFilter</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>ASYNC</dispatcher>
</filter-mapping>

这里指定了一个ASYNC的配置,表明过滤异步请求,这个ASYNC即是枚举类DispatcherType中的一个元素,在Servlet3.0中,如果一个请求是DispatcherType.ASYNC类型的,那么在一个单一请求的过程中,filter能够被多个线程调用,也就是意味着一个filter可能在一次请求中被多次执行,这显然是会有问题的,那么spring是怎么避免这个问题的呢?这就是今天要说的OncePerRequestFilter。

直接看doFilter方法

@Override
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {

   if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
      throw new ServletException("OncePerRequestFilter just supports HTTP requests");
   }
   HttpServletRequest httpRequest = (HttpServletRequest) request;
   HttpServletResponse httpResponse = (HttpServletResponse) response;

   String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
   boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;

   if (hasAlreadyFilteredAttribute || skipDispatch(httpRequest) || shouldNotFilter(httpRequest)) {

      // Proceed without invoking this filter...
      filterChain.doFilter(request, response);
   }
   else {
      // Do invoke this filter...
      request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
      try {
         doFilterInternal(httpRequest, httpResponse, filterChain);
      }
      finally {
         // Remove the "already filtered" request attribute for this request.
         request.removeAttribute(alreadyFilteredAttributeName);
      }
   }
}

从源码可以看出,spring会给已经过滤过的request设置一个attribute,在filter链和目标方法执行完毕之后才会释放这个attribute,attribute的名字是从  getAlreadyFilteredAttributeName() 方法得来,默认为filter的名字加后缀,如果filter没有完全初始化,则改为类名加后缀,后缀为“.FILTERED”

protected String getAlreadyFilteredAttributeName() {
   String name = getFilterName();
   if (name == null) {
      name = getClass().getName();
   }
   return name + ALREADY_FILTERED_SUFFIX;
}

获取完名字之后,需要进行判断是否已经执行过这个filter了,判断条件有3个

1 是否有hasAlreadyFilteredAttribute 

2 是否skipDispatch

3 是否不进行过滤

我们直接看2和3,步骤3里,根据shouldNotFilter(httpRequest)来判断是否进行过滤,其实现依赖于子类。

在2里面判断条件有两种

private boolean skipDispatch(HttpServletRequest request) {
   if (isAsyncDispatch(request) && shouldNotFilterAsyncDispatch()) {
      return true;
   }
   if (request.getAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE) != null && shouldNotFilterErrorDispatch()) {
      return true;
   }
   return false;
}

1 是异步并且不应该过滤异步,则skipDispatch为true,即不进行过滤

2 是ERROR请求并且不应该过滤ERROR,同样返回true

在上述所有判断条件完成之后,就可以决定是否执行

doFilterInternal(httpRequest, httpResponse, filterChain);

方法了,这个方法就是子类具体实现的方法,其中之一便是前一篇文章中讲的CharacterEncodingFilter。

还需要注意的一个方法是 

protected boolean isAsyncStarted(HttpServletRequest request) {
   return WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted();
}

如果这个返回true,那么当前线程结束时不会将response提交回去。

目录
相关文章
|
8天前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
46 3
|
6天前
|
前端开发 开发者 容器
构建响应式Web界面:Flexbox与Grid布局的深度解析
【10月更文挑战第11天】本文深入解析了CSS3中的Flexbox和Grid布局,探讨了它们的特点、应用场景及使用方法。Flexbox适用于一维布局,如导航栏;Grid布局则适用于二维布局,如复杂网格。通过示例代码和核心属性介绍,帮助开发者灵活构建响应式Web界面。
17 5
|
4天前
|
JavaScript Java 关系型数据库
自主版权的Java诊所管理系统源码,采用Vue 2、Spring Boot等技术栈,支持二次开发
这是一个自主版权的Java诊所管理系统源码,支持二次开发。采用Vue 2、Spring Boot等技术栈,涵盖患者管理、医生管理、门诊管理、药店管理、药品管理、收费管理、医保管理、报表统计及病历电子化等功能模块。
|
8天前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
30 5
|
10天前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
|
10天前
|
XML Java 数据格式
Spring底层架构源码解析(二)
Spring底层架构源码解析(二)
|
14天前
|
设计模式 测试技术 持续交付
开发复杂Web应用程序
【10月更文挑战第3天】开发复杂Web应用程序
28 2
|
16天前
|
Java PHP
PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。理解其垃圾回收机制有助于开发高效稳定的PHP应用。
【10月更文挑战第1天】PHP作为广受青睐的服务器端脚本语言,在Web开发中占据重要地位。其垃圾回收机制包括引用计数与循环垃圾回收,对提升应用性能和稳定性至关重要。本文通过具体案例分析,详细探讨PHP垃圾回收机制的工作原理,特别是如何解决循环引用问题。在PHP 8中,垃圾回收机制得到进一步优化,提高了效率和准确性。理解这些机制有助于开发高效稳定的PHP应用。
35 3
|
1月前
|
数据可视化 图形学 UED
只需四步,轻松开发三维模型Web应用
为了让用户更方便地应用三维模型,阿里云DataV提供了一套完整的三维模型Web模型开发方案,包括三维模型托管、应用开发、交互开发、应用分发等完整功能。只需69.3元/年,就能体验三维模型Web应用开发功能!
221 8
只需四步,轻松开发三维模型Web应用
|
1月前
|
安全 API 开发者
Web 开发新风尚!Python RESTful API 设计与实现,让你的接口更懂开发者心!
在当前的Web开发中,Python因能构建高效简洁的RESTful API而备受青睐,大大提升了开发效率和用户体验。本文将介绍RESTful API的基本原则及其在Python中的实现方法。以Flask为例,演示了如何通过不同的HTTP方法(如GET、POST、PUT、DELETE)来创建、读取、更新和删除用户信息。此示例还包括了基本的路由设置及操作,为开发者提供了清晰的API交互指南。
95 6

推荐镜像

更多