SpringMVC也是我们日常生活中常用的框架之一,熟悉SpringMVC的启动过程,有助于我们理解相关文件配置的原理,深入理解SpringMVC的设计原理和执行过程。
今天我们就以之前搭建的SpringMVC的demo作为案例,分析SpringMVC的源码以及启动流程,具体的demo可以看我之前的文章 SpringMVC源码分析之框架搭建
一、web应用部署流程
我们知道SpringMVC的启动是依赖于servlet容器的,而Spring的启动则是依赖于IOC容器,那么Spring MVC的启动必须要将servlet容器与IOC容器关联起来,那么这个过程是怎样的呢?
我们先看个一个标准的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">
<display-name>Archetype Created Web Application</display-name>
<!-- 初始化Spring ioC容器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- 默认的路径是/WEB-INF/applicationContext.xml,下面多个xml使用,分割-->
<param-value>classpath*:spring.xml</param-value>
</context-param>
<!-- 要使用Spring的ioC容器-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!--下面时定义前端控制器 DispatcherServlet 的内容-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置初始化时加载的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-mvc.xml</param-value>
</init-param>
<!--配置init的加载顺序-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--这是前端控制器 dispatcherServlet 对应的路径拦截配置,会拦截除jsp之外的路径-->
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
我们在部署web应用到容器(如tomcat)时,容器首先会加载web.xml里面的内容,主要是为了加载listener、context-param等标签,为什么我会这样说呢,我们可以先去官网上看一下SpringMVC的文档:
具体翻译过来是:当一个web应用部署到容器内时(如tomcat),在web应用开始响应执行用户请求前,以下步骤会被依次执行:
- 部署描述文件中(如tomcat的web.xml)由
<listener>
元素标记的事件监听器会被创建和初始化; - 对于所有事件监听器,如果实现了
ServletContextListener
接口,将会执行其实现的contextInitialized()
方法; - 部署描述文件中由
<filter>
元素标记的过滤器会被创建和初始化,并调用其init()
方法; - 部署描述文件中由
<servlet>
元素标记的servlet会根据<load-on-startup>
的权值按顺序创建和初始化,并调用其init()
方法。
由此可知,SpringMVC启动的时候应当是按照依次初始化加载listener->filter->servlet,这便是SpringMVC的启动流程,按照这个流程我们可以跟一下SpringMVC启动时的源码。
二、SpringMVC启动流程源码分析之ContextLoaderListener
上面我们知道了当SpringMVC启动时,容器(如tomcat)先去加载web.xml文件,然后对该文件进行解析,当遇到context-param标签时,会将里面的内容解析,然后去读取并解析对应的配置文件,获取其中的配置属性,然后放到application中,这是一个全局的变量,在后续创建listener
时会使用到这个全局变量。因此,Web应用在容器中部署后,进行初始化时会先读取这个全局变量,之后再进行上述讲解的初始化启动过程。
接着,SpringMVC开始解析listener
标签,去加载执行ContextLoaderListener的contextInitialized方法,ContextLoaderListener的继承关系图如下:
ContextLoaderListener用的是一种观察者模式,即走的是发布-订阅模式,他会执行其中的contextInitialized方法进行事件发布,这个事件就是开始初始化WebApplicationContext,其源码如下:
public void contextInitialized(ServletContextEvent event) {
//初始化WebApplicationContext,IOC容器
initWebApplicationContext(event.getServletContext());
}
从方法名initWebApplicationContext可以知道,该方法是用来初始化webApplicationContext,即IOC容器,具体的源码如下:
<