解析 SpringMVC 父子容器及九大内置组件加载过程

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 解析 SpringMVC 父子容器及九大内置组件加载过程

在解析整个 mvc 父子容器加载过程时,先了解一些基本的流程和知识,Spring MVC 启动需要 Tomcat 容器来进行嵌入,启动 Tomcat 容器->加载项目的 web.xml 文件->启动 Spring 容器->启动 Spring MVC 容器.

Tomcat 安装启动及 idea 如何配置可以搜索网上其他文章进行构建.

web.xml 入口

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-config.xml</param-value>
    </context-param>
    <servlet>
        <servlet-name>mvc-test</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--SpringMVC 配置文件 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-test</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

<context-param> 标签 contextConfigLocation 参数 配置的是 Spring 父容器的配置文件,<servlet> 标签下 contextConfigLocation 参数配置的是 Spring MVC 子容器的配置文件,load-on-startup 配置为 1 或者 0 代表的是启动 Tomcat 容器后要进行 Servlet 加载及初始化,配置为 -1 代表只有请求 servlet 时才会被加载及初始化

父容器

ContextLoaderListener 上下文加载监听器这个类就至关重要了,tomcat 启动以后会调用该类下的初始化方法 contextInitialized,用于启动父容器,流程图如下所示:

contextInitialized 方法会调用其父类 ContextLoader#initWebApplicationContext 方法,其下有静态代码块用于加载 spring-web 模块下的 ContextLoader.properties 文件.

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
  • 首先当前的 ServletContext 中是否包含 .ROOT 字符,如果包含则抛出异常,提示 web.xml 不能多次定义 ContextLoader
  • 创建上下文对象,实例化 XmlWebApplicationContext 类型,其父类为 AbstractRefreshableWebApplicationContext,在其构造方法内会设置具体的展示名称:setDisplayName(“Root WebApplicationContext”),标识其为 ROOT 父容器
  • 最后,完成上下文的属性设置工作以及调用 refresh 方法完成 xml 文件解析、bean 实例化/初始化工作
  • 解析当前 web.xml 文件中是否配置了 contextId 初始化参数,如果有就设置 id 为 contextId 参数值,否则就拼接当前类名+上下文路径作为 id 名称.
  • 设置 ServletContext,类型为 ApplicationContextFacade,其类型为 tomcat catelina 包下的
  • 设置环境对象的属性资源变量值:servletContextInitParams、servletConfigInitParams 以及 SystemProperties、SystemEnv.
    到此,spring 父容器已经加载完毕.

子容器

父容器加载完毕,接下来还需要将 spring mvc 子容器进行加载工作,相信学习过 servlet 知识的同学都知道,init->service->destroy 这三个方法是执行或调用 servlet 所必须经过的历程,所以首先我们要先找到核心的方法 init,spring mvc 核心处理类:DispatcherServlet,观察其源码发现其并没有重写 init 方法,那么就可以观察它的父类,总会有实现 init 方法的父类.

通过前面给出的 web.xml 文件,servlet 标签下包裹的类型为:org.springframework.web.servlet.DispatcherServlet,其下还配置了 init-param 指向的 Spring MVC 子容器需要进行解析的 xml 配置文件,Spring MVC 子容器详细的加载流程图如下:

  1. 因为 DispatcherServlet 类没有对应的 init 方法,所以一直找它的父类,FrameworkServlet 内也没有 init 方法,所以还是找它的父类 HttpServletBean:在它下面有调用 init 方法进行容器的加载工作.
  2. Spring MVC 子容器创建时和父容器过程是一摸一样的,只是在属性上的设置做了一些区分的动作,例如:
    添加监听器 SourceFilteringListener 到 wac 中,实际是通过 ContextRefreshListener 去监听对应的事件:ContextRefreshedEvent,当监听器接收到消息之后会调用 onApplicationEvent 方法,执行 onRefresh 方法,将 refreshEventReceived 标志设置为 true,表示已经 refresh 过,该事件的处理主要的目的就是为了完成 Spring MVC 九大内置组件的加载工作.
    当执行 AbstractApplicationContext#refresh 方法内的 finshRefresh 时,会发布上下文的刷新事件,然后 FremeworkServlet.ContextRefreshListener 监听器就会接收到事件对其进行处理工作.
  3. 除了在执行 refresh 方法时会触发事件的发布,在 Spring MVC 子容器加载完以后,会判断 refreshEventReceived 标志是否为 false:如果是,代表还没进行刷新工作,会手动调用 DispatcherServlet#onRefresh 方法执行.

对以上内容进行总结:Spring MVC 启动是依赖于 Tomcat 服务的,所以整体的加载流程(启动 Tomcat->加载 web.xml 文件->Spring 容器->Spring MVC 容器)完成以后,后面就只需要对其进行调用了.

九大内置组件对象

加载 DispatcherServlet 类时,会执行 static 静态代码块,DispatcherServlet.properties 加载这个文件的属性源,在 spring-web-mvc 模块中,resource 目录下的 resources/org/springframework/web/servlet/DispatcherServlet.properties,其文件内容如下:

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
  org.springframework.web.servlet.function.support.RouterFunctionMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
  org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
  org.springframework.web.servlet.function.support.HandlerFunctionAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
  org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
  org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

以下是 initStrageties 初始化策略器方法的执行流程图,如下:

  1. 初始化 MultipartResolver:主要用来处理文件上传,如果定义过当前类型的 bean 对象,那么直接获取,如果没有的话,可以为 null,一般使用的类:CommonsMultipartResolver
  2. 初始化 LocaleResolver:主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver),基于session的配置(SessionLocaleResolver),基于cookie的配置(CookieLocaleResolver)
  3. 初始化 ThemeResolver:主要用来设置主题 Theme,一般过节的时候,如:清明节或国家重要的节日,都是会切换主题背景的.
  4. 初始化 HandlerMapping 映射器:用来将对应的 request 跟 controller 进行对应
  5. 初始化 HandlerAdapter 处理适配器:主要包含 Http 请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器
  6. 初始化 HandlerExceptionResolver:基于 HandlerExceptionResolver 接口的异常处理
  7. 初始化 RequestToViewNameTranslator:当 controller 处理器方没有返回一个 View 对象或逻辑视图名称,并且在该方法中没有直接往 response 输出流里面写数据的时候,spring 将会采用约定好的方式提供一个逻辑视图名称
  8. 初始化 ViewResolver:将 ModelAndView 选择合适的视图进行渲染的处理器
  9. 初始化 FlashMapManager:提供请求存储属性,可供其他请求使用

总结

以上就是父子容器以及 Spring MVC 九大内置组件的加载过程详细解析.

如果觉得博文不错,关注我 vnjohn,后续会有更多实战、源码、架构干货分享!

大家的「关注❤️ + 点赞👍 + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下文见!

目录
相关文章
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
162 2
|
19天前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
27 1
|
24天前
|
缓存 前端开发 JavaScript
前端的全栈之路Meteor篇(二):容器化开发环境下的meteor工程架构解析
本文详细介绍了使用Docker创建Meteor项目的准备工作与步骤,解析了容器化Meteor项目的目录结构,包括工程准备、环境配置、容器启动及项目架构分析。提供了最佳实践建议,适合初学者参考学习。项目代码已托管至GitCode,方便读者实践与交流。
|
28天前
|
存储 应用服务中间件 云计算
深入解析:云计算中的容器化技术——Docker实战指南
【10月更文挑战第14天】深入解析:云计算中的容器化技术——Docker实战指南
52 1
|
29天前
|
存储 JavaScript 前端开发
Vue3权限控制全攻略:路由与组件层面的用户角色与权限管理方法深度解析
Vue3权限控制全攻略:路由与组件层面的用户角色与权限管理方法深度解析
104 2
|
30天前
|
机器学习/深度学习 编解码 算法
深入解析MaxFrame:关键技术组件及其对视频体验的影响
【10月更文挑战第12天】随着流媒体服务和高清视频内容的普及,用户对于视频质量的要求越来越高。为了满足这些需求,许多技术被开发出来以提升视频播放的质量。其中,MaxFrame是一种旨在通过一系列先进的图像处理算法来优化视频帧的技术。本文将深入探讨构成MaxFrame的核心组件,包括运动估计、超分辨率重建以及时间插值算法,并讨论这些技术如何协同工作以改善视频播放效果。
38 1
|
14天前
|
机器学习/深度学习 自然语言处理 数据管理
GraphRAG核心组件解析:图结构与检索增强生成
【10月更文挑战第28天】在当今数据科学领域,自然语言处理(NLP)和图数据管理技术的发展日新月异。GraphRAG(Graph Retrieval-Augmented Generation)作为一种结合了图结构和检索增强生成的创新方法,已经在多个应用场景中展现出巨大的潜力。作为一名数据科学家,我对GraphRAG的核心组件进行了深入研究,并在此分享我的理解和实践经验。
38 0
|
30天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
65 0
|
1月前
|
云计算 开发者 Docker
揭秘云计算中的容器化技术——Docker的深度解析
【10月更文挑战第6天】揭秘云计算中的容器化技术——Docker的深度解析

推荐镜像

更多