图解Spring:HTTP请求的处理流程与机制【3】

3. HTTP 请求在 Web 应用中的处理流程

在穿越了 Web 容器之后,HTTP 请求将被投送到 Web 应用,我们继续以 Tomcat 为例剖析后续流程。Web 容器与 Web 应用的衔接是通过配置文件 web.xml 完成的。web.xml 是遵循 Java Servlet 标准规范的配置文件,我们通过这份配置文件定义构成 Web 应用的各种核心组件和初始化配置,其中包括:过滤器 Filter、监听器 Listener、伺服器 Servlet 等等。不同组件分别承担不同的功能,在介绍 Web 应用处理 HTTP 请求流程之前,我们照例先来了解一下这些核心组件。

创新互联建站专业提供服务器托管服务,为用户提供五星数据中心、电信、双线接入解决方案,用户可自行在线购买服务器托管服务,并享受7*24小时金牌售后服务。

3.1 Web 应用核心组件简介

3.1.1 过滤器 Filter

过滤器 Filter 负责对 HTTP 请求做预处理,接着将请求交给 Servlet 进行处理并生成响应,最后 Filter 再对响应进行后处理。从 HTTP 请求的处理过程来看,Filter 主要参与以下几个环节:

  • 在 HttpServletRequest 到达 Servlet 之前,拦截客户的 HttpServletRequest。
  • 根据需要检查 HttpServletRequest,也可以修改 HttpServletRequest 报文头和数据。
  • 在 Servlet 生成的 HttpServletResponse 抵达客户端之前,拦截 HttpServletResponse。
  • 根据需要检查 HttpServletResponse,也可以修改 HttpServletResponse 报文头和数据。

过滤器映射 filter-mapping,用于声明 Web 应用将会用到的过滤器,过滤器可被映射到一个 Servlet 或 URL 模式。如果将过滤器映射到一个 Servlet 上,那它就作用于特定 Servlet。如果将过滤器映射到一个 URL 模式,那么它将作用于任何资源,只要该资源的 URL 与 URL 模式匹配。如果对某个资源的请求匹配到多个 Filter,那么在处理 HTTP 请求过程中,Tomcat 将按照过滤器映射 filter-mapping 在配置文件 web.xml 中的先后顺序来执行,在前面的先执行,在后面的后执行,多个过滤器 Filter 可以组成调用链。URL 模式匹配有三种类型规则:

  • 精确匹配:如“/foo.htm”,那只会匹配“foo.htm”这个 URL。
  • 路径匹配:如“/foo/*”,那只会匹配以 foo 为前缀的 URL。
  • 后缀匹配:如“*.htm”,那只会匹配所有以“.htm”为后缀的 URL。

    encodingFilter
    org.springframework.web.filter.CharacterEncodingFilter
    
        encoding
        UTF-8
    
    
        forceEncoding
        true
    


    encodingFilter
    /*  
3.1.2 监听器 Listener

监听器 Listener 主要用于监听 Application、Session、Request 等对象的变化,每当这些对象发生变化就会回调用对应的监听方法。例如:在 Servlet API 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期。当 Servlet 容器启动或终止Web 应用时,会触发 ServletContextEvent 事件,该事件由 ServletContextListener 来处理。


    org.springframework.web.util.Log4jConfigListener
3.1.3 伺服器 Servlet

伺服器 Servlet 负责处理客户端访问动态资源的 HTTP 请求,接口 javax.servlet.Servlet 定义了所有 Servlet 必须要实现的方法。

方法名称功能说明
destroy() 由 Servlet 容器调用,用于关闭停止 Servlet 提供的服务
getServletConfig() 获取 Servlet 初始化和启动时参数的配置信息对象 ServletConfig
getServletInfo() 获取 Servlet 的说明信息,包括:作者、版本和版权等等
init() 由 Servlet 容器调用,籍由配置 ServletConfig 完成 Servlet 初始化,启动对外服务
service() 由 Servlet 容器调用,让 Servlet 处理某个 HTTP 请求

从 HTTP 请求的处理过程来看,伺服器 Servlet 主要参与以下几个环节:

  • 接收请求:客户端请求会被封装成 HttpServletRequest 对象,包含报文头参数和报文体等信息。
  • 处理请求:通常调用 Servlet 的方法 service、doPost 或 doGet 等方法处理请求,并进一步调用业务层相应逻辑对其进行处理等。
  • 反馈响应:处理完请求后,可以转发(forward)、重定向(redirect)到某个视图页面或者直接返回结果数据,转发是 HttpServletRequest 的方法,重定向是 HttpServletResponse 的方法。

在老兵哥的读书年代,Web 应用相对简单,主要是各种信息管理系统。当时 Spring 尚未诞生,主流技术栈是 JSP/Servlet,老兵哥我开发 Web 应用时主要编写继承自 HttpServlet 子类,将各种业务逻辑功能分别交由不同的 HttpServlet 子类实现。HttpServlet 继承自 GenericServlet,后者实现了接口 Servlet。随着数字化和互联网化的不断推进,业务系统变得越来越复杂,HttpServlet 子类越写越多,web.xml 配置文件越来越复杂,这导致系统的扩展维护越来越困难,手工作坊式的开发方法已经跟不上业务发展的步伐了。时势造英雄,Spring 就是在这种背景下呼之而出的,它创造性地发明了控制反转 IOC 和面向切面编程 AOP,极大地降低复杂度。如下面配置示例所示,整个 Web 应用只需要配置一个 Servlet 就可以了,它就是 Spring 的前置分发器 DispatcherServlet:


    mvc
    org.springframework.web.servlet.DispatcherServlet
    
        contextConfigLocation
        classpath:mvc-servlet.xml
    
    1


    mvc
    /api

3.2 Web 应用处理 HTTP 请求的流程

如下图所示,Web 应用处理 HTTP 请求的流程主要是穿越监听器 Listener 和过滤器链 Filters,最终抵达伺服器 Servlet 的过程:
图解 Spring:HTTP 请求的处理流程与机制【3】
原先我们将 Web 应用的复杂度直接暴露给了 Tomcat,现在 Spring 通过控制反转 IOC 和面向切面编程 AOP 等新技术接管了 Web 应用的复杂度。如前面 Servlet 的配置示例,整个 Web 应用只需要配置 Spring 提供的前置分发器 DispatcherServlet,开发者无需再编写和配置 HttpServlet 子类,所有业务逻辑功能将按照 Spring 的标准规范来开发,从原先的编写 Listener\Filter\Servlet 改为编写 Spring Component,包括:Controller、Service、Repository 等。

Tomcat 在接收到某个 Web 应用的 Http 请求之后,它会将所有请求都转交给前置分发器 DispatcherServlet,再由 DispatcherServlet 将请求派发给具体业务逻辑进行处理。DispatcherServlet 就是从 HttpServlet 派生的子类,它的类图关系如下所示:
图解 Spring:HTTP 请求的处理流程与机制【3】

3.3 Web 应用架构演进过程解析

Web 应用架构的演进过程就像创业孵化过程,最初创业团队打造的产品很简单,大家采用手工作坊模式来快速打造最小化可行产品,这时候团队的组织架构也跟产品一样扁平简单。但随着产品被越来越多的用户使用,功能变得越来越复杂,接着必须引进新架构才能有效管理复杂度,同时团队规模的扩展也需要与业务发展匹配的组织架构,这样才能保证产品的不断发展。Web 应用架构的演化过程跟 Tomcat 体系结构的形成过程类似,老兵哥会经常借助“俄罗斯套娃”这个模型来阐述架构,Web 容器和 Web 应用这两层的架构原则是类似的,就像大娃娃套着小娃娃一样。

Spring 的 IOC 容器跟 Tomcat 的 Servlet 容器类似,也是通过配置文件等方式来定义组件,然后在启动过程中将这些定义好的组件初始化并添加到容器当中,后续使用时从容器查找获取。早期 Web 应用主要由大量开发者编写的 Filter\Listener\Servlet 等组件构成,这些核心组件的配置全部都通过 web.xml 配置文件来维护,那么 Web 应用和 Web 容器之间其实不是松耦合的,而引进 Spring 之后就变成只需要配置 DispatcherServlet 等少量组件了,达到了分层架构的要求,更加有利于开发复杂的 Web 应用。如果采用架构的专业术语来描述,这就是经典的分层架构模式,层与层之间松耦合,仅通过少量的接口衔接,每层内部高内聚。

本文主要价值是帮助大家梳理出端到端的全流程框架,也就是我们常说的全局视角或者上帝视角。有了这个框架之后,我们可以根据自己的需要按图索骥找相关节点的资料来研究学习,不至于陷入细节找不到方向。当然,考虑到我们每个人的工作学习情况不同,平时遇到的问题也不同,本文内容无法覆盖所有人遇到的问题,欢迎大家留言提问,也欢迎关注我的博客或公号“IT老兵哥”交流互动,我会尽力尽快解答大家提出的问题,谢谢!

本系列其他文章索引如下:

  • 图解 Spring:HTTP 请求的处理流程与机制【1】
  • 图解 Spring:HTTP 请求的处理流程与机制【2】
  • 图解 Spring:HTTP 请求的处理流程与机制【4】
  • 图解 Spring:HTTP 请求的处理流程与机制【5】

当前名称:图解Spring:HTTP请求的处理流程与机制【3】
路径分享:http://hbruida.cn/article/pisiph.html