一、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监听器。