ContextLoader,ContextLoaderListener解读

一、ServletContext
addListener(..) 方法,也有创建的方法 createListener(Class<T> c)
addFilter(..) 方法,也有创建的方法。
可以获取路径,也可以获取其中的Servlet。可以获取资源,获取文件的MIME类型等等。
 
二、ServletContextListener
在ServletContext发生Event时,接收Event通知。
有两个方法:
// 在ServletContext进行初始化时执行。是在任何filter或者Servlet初始化之前。
public void contextInitialized(ServletContextEvent sce);

// 在ServletContext销毁时执行。是在所有的filter和Servlet销毁之后进行。
public void contextDestroyed(ServletContextEvent sce);
 
三、org.springframework.web.context.ContextLoader
public class ContextLoader
文档描述如下:
  执行root application context的实际初始化工作。由ContextLoaderListener调用。
  会先去查找web.xml中context-param级别的contextClass参数,该参数指定了context class类型,如果找不到,会使用XmlWebApplicationContext。
  默认情况下,所有context class都需要实现ConfigurableWebApplicationContext。(除非自行写了一个新的ContextLoader,见下面的代码第三行)
1     protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
2         Class<?> contextClass = determineContextClass(sc);
3         if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
4             throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
5                     "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
6         }
7         return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
8     }
  处理context-param的contextConfigLocation参数,传值给context实例,解析成多个文件路径(该参数可以使用逗号和空格设置多个值)。支持Ant风格。
  如果没指定,使用context class中默认的位置。例如,XmlWebApplicationContext使用 /WEB-INF/applicationContext.xml 。
 
  除了加载root application context之外,这个class还可以加载或获取并勾连到一个共享的父context。--就是给这个context设置一个父context。
 
 
四、现在再来看org.springframework.web.context.ContextLoaderListener
public class ContextLoaderListener extends ContextLoader implements ServletContextListener
文档描述如下:
  Bootstrap listener to start up and shut down Spring's root WebApplicationContext. Simply delegates to ContextLoader as well as to ContextCleanupListener. 
  引导监听器,用于启动和关闭Spring的根WebApplication上下文。
 
注意,该类除了两个构造方法之外,就只有重写了的ServletContextListener接口的两个方法。
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    public ContextLoaderListener() {
    }

    public ContextLoaderListener(WebApplicationContext context) {
        super(context);
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {
        initWebApplicationContext(event.getServletContext());
    }

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

}
 
就是说,当ServletContext初始化时,会执行contextInitialized(..),然后 initWebApplicationContext(..)
  -- 这个方法【initWebApplicationContext(..)】先会去创建一个webApplicationContext,并设置父context(可能)。然后配置并刷新这个webApplicationContext,并将其以【WebApplicationContext.class.getName() + ".ROOT"】为key设为servletContext的属性。
 
 
那个带参构造是什么意思,什么情况需要通过webApplicationContext来构造?? -- 进入了一个思维盲区!该构造的目的是通过listener实例来注册listener(而非通过类名)
带参构造的官方文档:
  使用给定的application context创建一个新的ContextLoaderListener。
  在Servlet 3.0+ 环境中有用。
  通过listener实例来注册listener(而非通过类名),见 javax.servlet.ServletContext.addListener 。
 
配合 initWebApplicationContext(..) 中的这个判断就明白了:
if (this.context == null) {
     this.context = createWebApplicationContext(servletContext);
}
就是说,如果已有application context,就不再创建,直接使用已有的。但是该设置的一样设置。
 
总结:
ContextLoaderListener 这个类的作用是,通过监听创建并设置WebApplicationContext。嗯,记住,这是一个ServletContext监听器。
 
 
原文地址:https://www.cnblogs.com/larryzeal/p/5885739.html