springmvc从入门到源码分析专题2_tomcat服务启动过程中如何加载ContextLoaderListener的

返回专题目录

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是如何被执行的

返回专题目录

猜你喜欢

转载自blog.csdn.net/u013328649/article/details/111628687