springmvc从入门到源码分析专题2_tomcat服务启动过程中如何加载ContextLoaderListener的
前言
在上一篇文章中我们做了相关前期准备,并且搭建好了我们的项目环境,成功运行了我们第一个springmvc项目helloword,但是我们并没有对我们的配置文件中的配置进行详解和分析,本篇文章及后面的文章我们将分析讲解这些配置的作用,并深入到源码讲解这些配置是如何实现的
ServletContext的作用
-
这里首先来说一下
ServletContext
的作用,因为它对后面我们分析org.springframework.web.context.ContextLoaderListener
很重要. -
ServletContext,是一个全局的储存信息的空间,服务器开始,其就存在,服务器关闭,其才释放。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。
-
启动web容器后,web容器会读取web.xml中的配置信息,对ServletContext进行信息补充。(注:配置加载顺序为:context-param -> listener -> filter -> servlet)
ServletContextListener 的作用
ServletContextListener 是 ServletContext 的监听者,用于接收有关ServletContext生命周期更改的通知事件的接口。监听 ServletContext 发生变化,如服务器启动时 ServletContext 被创建,服务器关闭时 ServletContext 要被销毁。
ContextLoaderListener 的源码解析
- 首先我们来看一下web.xml中是如何配置
org.springframework.web.context.ContextLoaderListener
<!-- 使用ContextLoaderListener配置时,需要告诉它Spring配置文件的位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--
配置上下文载入器,上下文载入器载入除DispatherServlet载入的配置文件之外的其他上下文配置文件
最常用的上下文载入器是一个Servlet监听器,器名称为ContextLoaderListener
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
- ContextLoaderListener 的源码
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
private ContextLoader contextLoader;
...
/**
* Initialize the root web application context.
*/
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
protected ContextLoader createContextLoader() {
return null;
}
...
}
-
从
ContextLoaderListener
的源码中我们看到它实现了ServletContextListener
接口,那么在容器启动的过程必然会调用ContextLoaderListener#contextInitialized(...)
方法,容器关闭时调用ContextLoaderListener#contextDestroyed(...)
方法 -
那么
ContextLoaderListener#contextInitialized(...)
方法的作用主要是做什么呢?它的作用主要是初始化WebApplicationContext
,从该方法中调用initWebApplicationContext(...)
方法的注释就可以看出,那就究竟是如何做的呢,我们继续往下看 -
ContextLoader#initWebApplicationContext(...)
的代码片段
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
...
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
...
// 配置并刷新WebApplicationContext
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
configureAndRefreshWebApplicationContext(cwac, servletContext);
...
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
...
return this.context;
}catch (RuntimeException ex) {
...
}
-
ContextLoader#createWebApplicationContext(...)
的代码片段
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
//获取 org.springframework.web.context.support.XmlWebApplicationContext 的class
Class<?> contextClass = determineContextClass(sc);
...
//通过反射创建WebApplicationContext对象
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
-
在
ContextLoader#initWebApplicationContext(...)
中,首先判断在servletContext中是否存在WebApplicationContext
,如果存在则就抛出异常,然后判断上下问对象是否为空,程序第一次执行时,该对象就是空的,然后调用ContextLoader#createWebApplicationContext(...)
创建WebApplicationContext
对象,然后调用ContextLoader#configureAndRefreshWebApplicationContext(...)
方法配置并刷新WebApplicationContext上下文 -
ContextLoader#configureAndRefreshWebApplicationContext(...)
方法的代码片段
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
...
//将ServletContext对象保存到上下文中
wac.setServletContext(sc);
//获取web.xml中配置的contextConfigLocation的值
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
....
// 刷新WebApplicationContext上下文
wac.refresh();
}
- 接下来就是将
WebApplicationContext
对象设置到servletContext
中,方便后面使用,这就是org.springframework.web.context.ContextLoaderListener
的作用
总结
通过上面分析我们不难看出org.springframework.web.context.ContextLoaderListener
的作用就是为了加载我们在web.xml中通过contextConfigLocation
指定的spring bean配置文件,创建根WebApplicationContext上下文,好了,本篇文章就到这里了,下一篇我们将分析容器启动过程中org.springframework.web.servlet.DispatcherServlet
是如何被执行的
网友评论