Spring之ContextLoaderListener的作用

Posted juncaoit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring之ContextLoaderListener的作用相关的知识,希望对你有一定的参考价值。

  在读公司的源码的时候,遇见这个问题,就了解一番。

  用法如下:

1 public class PlatformContextLoaderListener extends ContextLoaderListener {
2 
3     @Override
4     public void contextInitialized(ServletContextEvent event) {
5         PlatApplicationContext.initProjectConfig();
6         super.contextInitialized(event);
7     }
8 }

一:介绍

1.说明

  Spring org.springframework.web.context.ContextLoaderListener

  public class ContextLoaderListener extends ContextLoader implements ServletContextListener

  作用:在启动Web容器时,自动装配Spring applicationContext.xml的配置信息。

  因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。

  

2.关于ServletContextListener

  上文说过,在容器启动的时候,会默认执行她实现的方法。

  在我们公司的程序中,先写了我们自己需要走的程序,然后再写了super.contextInitialized(ServletContextEvent sce)方法。

 1 /*
 2  * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
 3  * Copyright 2004 The Apache Software Foundation
 4  *
 5  * Licensed under the Apache License, Version 2.0 (the "License");
 6  * you may not use this file except in compliance with the License.
 7  * You may obtain a copy of the License at
 8  *
 9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package javax.servlet;
19 
20 import java.util.EventListener;
21 
22 /** 
23  * Interface for receiving notification events about ServletContext
24  * lifecycle changes.
25  *
26  * <p>In order to receive these notification events, the implementation
27  * class must be either declared in the deployment descriptor of the web
28  * application, annotated with {@link javax.servlet.annotation.WebListener},
29  * or registered via one of the addListener methods defined on
30  * {@link ServletContext}.
31  *
32  * <p>Implementations of this interface are invoked at their
33  * {@link #contextInitialized} method in the order in which they have been
34  * declared, and at their {@link #contextDestroyed} method in reverse
35  * order.
36  *
37  * @see ServletContextEvent
38  *
39  * @since Servlet 2.3
40  */
41 public interface ServletContextListener extends EventListener {
42 
43     /**
44      * Receives notification that the web application initialization
45      * process is starting.
46      *
47      * <p>All ServletContextListeners are notified of context
48      * initialization before any filters or servlets in the web
49      * application are initialized.
50      *
51      * @param sce the ServletContextEvent containing the ServletContext
52      * that is being initialized
53      *
54      * @implSpec
55      * The default implementation takes no action.
56      */
57     default public void contextInitialized(ServletContextEvent sce) {}
58 
59     /**
60      * Receives notification that the ServletContext is about to be
61      * shut down.
62      *
63      * <p>All servlets and filters will have been destroyed before any
64      * ServletContextListeners are notified of context
65      * destruction.
66      *
67      * @param sce the ServletContextEvent containing the ServletContext
68      * that is being destroyed
69      *
70      * @implSpec
71      * The default implementation takes no action.
72      */
73     default public void contextDestroyed(ServletContextEvent sce) {}
74 }

 

3.再看看ContextLoader

  关注API,下面的三个阶段还是有点难理解,程序太多,在第二部分再描述。

  第一段说明ContextLoader可以由 ContextLoaderListener和ContextLoaderServlet生成。如果查看ContextLoaderServlet的API,可以看到它也关联了ContextLoader这个类而且它继承了HttpServlet

  第二段,ContextLoader创建的是 XmlWebApplicationContext这样一个类,它实现的接口是WebApplicationContext->ConfigurableWebApplicationContext->ApplicationContext->BeanFactory这样一来spring中的所有bean都由这个类来创建

  第三段,讲如何部署applicationContext的xml文件,如果在web.xml中不写任何参数配置信息,默认的路径是"/WEB-INF/applicationContext.xml,在WEB-INF目录下创建的xml文件的名称必须是applicationContext.xml。如果是要自定义文件名可以在web.xml里加入contextConfigLocation这个context参数:

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      /WEB-INF/classes/applicationContext-*.xml
    </param-value>
  </context-param>

  在<param-value> </param-value>里指定相应的xml文件名,如果有多个xml文件,可以写在一起并一“,”号分隔。上面的applicationContext-*.xml采用通配符,比如这那个目录下有applicationContext-ibatis-base.xml,applicationContext-action.xml,applicationContext-ibatis-dao.xml等文件,都会一同被载入。

 

4.多配置文件的情况

   <listener>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   </listener>

  如果applicationContext.xml文件没有在/WEB-INF/下,或文件名不一致,或存在多个Spring配置文件,在web.xml文件中根据下面代码修改

    <context-param>
       <param-name>contextConfigLocation</param-name>
       <param-value>classpath*:applicationContext-*.xml,/WEB-INF/applicationContext.xml,/WEB-INF/classes/applicationContext-*.xml
                  </param-value>
    </context-param>

 

二:ContextLoaderListener加载过程

  ContextLoaderListener实现了ServletContextListener接口,ServletContextListener是Java EE标准接口之一,类似tomcat,jetty的java容器启动时便会触发该接口的contextInitialized。

  1 java容器启动触发ContextLoaderListener的contextInitialized

  2 contextInitialized 方法调用ContextLoader的initWebApplicationContext方法。

  3 initWebApplicationContext调用createWebApplicationContext方法

  4 createWebApplicationContext 调用determineContextClass方法

    显然是从defaultStrategies中加载的

 1 /**
 2      * Return the WebApplicationContext implementation class to use, either the
 3      * default XmlWebApplicationContext or a custom context class if specified.
 4      * @param servletContext current servlet context
 5      * @return the WebApplicationContext implementation class to use
 6      * @see #CONTEXT_CLASS_PARAM
 7      * @see org.springframework.web.context.support.XmlWebApplicationContext
 8      */
 9     protected Class<?> determineContextClass(ServletContext servletContext) {
10         String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
11         if (contextClassName != null) {
12             try {
13                 return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
14             }
15             catch (ClassNotFoundException ex) {
16                 throw new ApplicationContextException(
17                         "Failed to load custom context class [" + contextClassName + "]", ex);
18             }
19         }
20         else {
21             contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
22             try {
23                 return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
24             }
25             catch (ClassNotFoundException ex) {
26                 throw new ApplicationContextException(
27                         "Failed to load default context class [" + contextClassName + "]", ex);
28             }
29         }
30     }

  ContextLoader 类中有段静态代码:

 1 private static final Properties defaultStrategies;
 2 
 3     static {
 4         // Load default strategy implementations from properties file.
 5         // This is currently strictly internal and not meant to be customized
 6         // by application developers.
 7         try {
 8             ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
 9             defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
10         }
11         catch (IOException ex) {
12             throw new IllegalStateException("Could not load ‘ContextLoader.properties‘: " + ex.getMessage());
13         }
14     }

  ContextLoader.properties 文件内容如下:

1 org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

  至此,determineContextClass方法返回的是XmlWebApplicationContext

6 回到 initWebApplicationContext 方法,调用configureAndRefreshWebApplicationContext方法

7 configureAndRefreshWebApplicationContext 调用了AbstractApplicationContext的refresh方法

8 refresh 方法调用了obtainFreshBeanFactory

9 obtainFreshBeanFactory 调用了AbstractRefreshableApplicationContext类的refreshBeanFactory方法

10 refreshBeanFactory调用了XmlWebApplicationContext的loadBeanDefinitions

11 loadBeanDefinitions中加载了对应的applicationContext.xml

 

 

 

参考文档:

1.https://www.cnblogs.com/hello-yao-ge/p/5891435.html

2.https://blog.csdn.net/MrZhangXL/article/details/78587426

  

 

以上是关于Spring之ContextLoaderListener的作用的主要内容,如果未能解决你的问题,请参考以下文章

ContextLoaderListener 与否?

Java实战之03Spring-02Spring的核心之IoC

Spring源码窥探之:Spring IOC之@Value

风暴之Spring事务

我们一起学习Spring之Spring简介

Spring系列之手写一个SpringMVC