web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- 省略非关键的配置 -->

<!-- [1] Spring配置 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 指定Spring Bean的配置文件所在目录,默认配置在WEB-INF目录下。该 <context-param> 标签会被设置到 ServletContext 中-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/applicationContext.xml</param-value>
</context-param>

<!-- ====================================== -->

<!-- [2] Spring MVC配置 -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如spring-servlet.xml
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value> // 默认
</init-param>
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
  • [1]处配置了org.springframework.web.context.ContextLoaderListener对象,它实现了javax.servlet.ServletContextListener接口,会初始化一个Root WebApplicationContext容器;
  • [2]处配置了org.springframework.web.servlet.DispatcherServlet对象,它实现了javax.servlet.http.HttpServlet,除了拦截我们制定的*.do请求外,也会初始化一个属于它的 Servlet WebApplicationContext 容器,并且这个容器是以 [1] 处的 Root 容器作为父容器。

下面就以上两个容器进行分析,一个是业务容器,一个是Web容器。

Root WebApplicationContext

Root WebApplicationContext也就是业务容器,用于加载业务逻辑相关的类,比如service、dao层的一些类。它的初始化是通过ContextLoaderListener来实现,在Servlet容器启动时,例如Tomcat、Jetty启动,则会被ContextLoaderListener监听到,从而调用contextInitialized(ServletContextEvent event)方法,初始化Root WebApplicationContext容器。它的核心配置如下:

1
2
3
4
5
6
7
8
9
<!-- [1] Spring配置 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 指定Spring Bean的配置文件所在目录。默认配置在WEB-INF目录下 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/applicationContext.xml</param-value>
</context-param>

如上,ContextLoaderListener可通过ServletContext获取到contextConfigLocation配置。这样,业务容器就可以加载application.xml配置文件了。

ContextLoaderListener

org.springframework.web.context.ContextLoaderListener,实现ServletContextListener接口,继承ContextLoader类,上面说过,它实现了Servlet容器启动和关闭时,分别初始化和销毁WebApplicationContext容器。

对于ContextLoaderListener,它的初始化和销毁的真正逻辑其实是由父类ContextLoader实现的。

  • 初始化WebApplicationContext容器:

    1
    2
    3
    4
    5
    6
    7
    // ContextLoaderListener.java

    @Override
    public void contextInitialized(ServletContextEvent event) {
    // 初始化 WebApplicationContext,调用父类实现的方法
    initWebApplicationContext(event.getServletContext());
    }
  • 销毁WebApplicationContext容器:

    1
    2
    3
    4
    5
    6
    7
    // ContextLoaderListener.java

    @Override
    public void contextDestroyed(ServletContextEvent event) {
    closeWebApplicationContext(event.getServletContext());
    ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }

Servlet WebApplicationContext

Servlet WebApplicationContext也就是Web容器,它的初始化是在DispatcherServlet初始化的过程中执行,并且会将业务容器作为父容器,之所以这样是因为Web容器中的一些Bean会依赖于业务容器中的Bean,比如我们的controller层接口通常会依赖service层的业务逻辑类。

以下是这个继承体系中各个类负责的任务,结构还是比较清晰的:

  • HttpServletBean:覆写了父类HttpServlet中的init()方法,是创建Web容器的入口,负责将ServletConfig设置到HttpServletBean的子类对象中(比如DispatcherServlet)。类上的简单注释如下:

    1
    2
    3
    4
    5
    6
    7
    // HttpServletBean.java

    /**
    * Simple extension of {@link javax.servlet.http.HttpServlet} which treats
    * its config parameters ({@code init-param} entries within the
    * {@code servlet} tag in {@code web.xml}) as bean properties.
    */
  • FrameworkServlet:覆写了父类HttpServletBean中的initServletBean()方法,负责初始化Servlet WebApplicationContext容器。类上的简单注释如下:

    1
    2
    3
    4
    5
    6
    // FrameworkServlet.java

    /**
    * Base servlet for Spring's web framework. Provides integration with
    * a Spring application context, in a JavaBean-based overall solution.
    */
  • DispatcherServlet:负责初始化Spring MVC的各个组件,以及处理客户端的请求。类上的简单注释如下:

    1
    2
    3
    4
    5
    6
    7
    // DispatcherServlet.java

    /**
    * Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers
    * or HTTP-based remote service exporters. Dispatches to registered handlers for processing
    * a web request, providing convenient mapping and exception handling facilities.
    */

参考资料