SpringMVC流程分析(一):从一行配置入手,搞懂web环境下Ioc容器的构建
本系列文章皆在分析SpringMVC的核心组件和工作原理,让你从springmvc浩如烟海的代码中跳出来,以一种全局的视角来重新审视SpringMVC的工作原理SpringMVC。
思考,输出,沉淀。用通俗的语言陈述技术,让自己和他人都有所收获。
作者:毅航😜
前言
随着 Spring Boot 和 Spring Cloud 在开发中的普及,极大的简化了web开发的上手难度。可能你已经忘记当年经典的 Servlet + Spring MVC 的组合,忘记了那个繁琐配置 web.xml 时代。
本文将从web.xml文件中的一行简单配置开始分析,从细节着手,重新来分析 Servlet 是怎么和 Spring MVC 进行集成并完成Spring 容器初始化工作的。
下图展示了本系列文章重点分析的组件信息,其中 ContextLoaderListener是本文分析的重点。

熟悉又陌生的配置文件
在使用Spring MVC之前,通常我们会在web.xml文件中配置一个叫做ContextLoaderListener的监听器,具体配置如下。
org.springframework.web.
context.ContextLoaderListener
SpringMVC作为web容器, 其核心本质就是对servlet 的封装和处理, 所以必定需要一个servlet容器,自然而然就想到了其的使用肯定需要借助于Tomcat的帮助。
而Tomcat的基本工作流程为,加载web.xml,解析其中内容,而其中配置有Spring,SpringMVC的配置文件信息,所以我们选择ContextLoaderListener作为入口,来探究和分析SpringMVC的启动流程。
在开始之前,我们不妨先思考一个问题,那这个监听器择ContextLoaderListener具体有什么作用呢?接下来,我们将带着这个问题来重新审视ContextLoaderListener这个组件。
监听器
监听器(Listener)是Servlet体系下的一个组件,其主要可用于监听和响应Web应用程序中事件的组件。它可以监听Servlet、Session、请求、上下文等不同级别的事件,并在事件发生时执行相应的逻辑。而组件ServletContextListener定义了方法contextInitialized和contextDestroyed分别用来监听ServletContext的创建和销毁。
回到我们之前讨论的ContextLoaderListener,其有如下的继承体系结构。

具体来看,ContextLoaderListener实现了javax.servlet.ServletContextListener接口,这保证了其可用于监听ServletContext的生命周期事件。
其外,由于ContextLoader是Spring中的一个辅助类,它用于在Web应用程序启动时加载Spring的应用上下文信息。它主要用于创建和初始化Spring的根应用上下文,以及将其关联到ServletContext中,使得在整个Web应用程序中可以共享和重用Spring的Bean。
至此,我们可以大致明白SpringMVC一定程度上可以正常工作,其主要通过事件监听的模式来实现,而监听器正常工作,通常需要几大关键信息:即被监听对象,事件,监听器。 此时,ContextLoaderListener就相当于一个监听器,被监听的对象则是ServletContext,而事件则是Tomcat容器启动。
对于ContextLoaderListener的类结构信息,我们需要强调的是:
ServletContext对象是Tomcat的ServletContextListener是Tomcat提供的接口ContextLoaderListener则是Spring写的,并实现了ServletContextListener
Web环境中Ioc容器的构建
由于ContextLoaderListner实现了ServletContextListener接口,所以当Tomcat中的ServletContext创建时,便会触发一个创建ServletContextEvent事件,此时ContextLoaderListener便会监听到该事件,从而执行其中的contextInitialized(),而这个方法内部的initWebApplicationContext()就是用来初始化Spring的IOC容器的。
public class ContextLoaderListener
extends ContextLoader implements ServletContextListener {
/**
* 初始化web容器
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
其中方法initWebApplicationContext的逻辑如下
public WebApplicationContext initWebApplicationContext(ServletContext
servletContext) {
// ... 省略异常捕获,条件判断
if (this.context == null) {
// 创建一个web容器
this.context = createWebApplicationContext(servletContext);
}
// ... 省略异常捕获,条件判断
// 加载配置文件中context-param信息,刷新spring容器
configureAndRefreshWebApplicationContext(cwac, servletContext);
return this.context;
}
在上述代码中,我们剔除掉了大量无关代码,不难发现initWebApplicationContext主要做了两件事:
- 创建一个web容器
- 加载spring配置文件,完成容器刷新工作
经过这一套流程处理下来,Spring的IOC容器也就初始化完成,同时还会构建一个Web环境的容器WebApplicationContext容器信息。
总结
ContextLoaderListener的作用是监听Web应用程序的启动和销毁事件,同时在Web容器启动时从web.xml中获取Spring的相关配置文件,完成bean的初始化。
其实ContextLoaderListener更像一个桥梁,保证了Spring和SpringMVC之间的整合。事实上,如果仅使用SpringMVC,而不使用Spring的其他功能(例如Spring的IoC容器和Bean管理等),则在配置文件中配置ContextLoaderListener是可选的。
例如,如果仅创建Controller来处理请求和渲染视图,通常不需要显式配置ContextLoaderListener。因为DispatcherServlet自动创建一个子级的容器,并管理与SpringMVC相关的组件信息,如控制器、拦截器等。