美文网首页
springmvc从入门到源码分析专题2_tomcat服务启动过

springmvc从入门到源码分析专题2_tomcat服务启动过

作者: wulin_challenge | 来源:发表于2020-12-24 14:35 被阅读0次

返回专题目录

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

返回专题目录

相关文章

网友评论

      本文标题:springmvc从入门到源码分析专题2_tomcat服务启动过

      本文链接:https://www.haomeiwen.com/subject/dpsmnktx.html