<listener>
<listener-class>com.jd.listener.MyServletContextLisenter</listener-class>
</listener>
写一个类,继承 一个listener接口,实现方法
public class MyServletContextLisenter implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce) {
ServletContext servletContex = sce.getServletContext();
System.out.println("contextInitialized..."+servletContex);
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("contextDestroyed...");
}
}
<?xml version="1.0" encoding="UTF-8"?>
...省略<web-app>标签...
<display-name>cassini</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 配置spring核心监听器,默认会以 /WEB-INF/applicationContext.xml作为配置文件 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!—contextConfigLocation用于指定Spring的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</context-param>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextAttribute</param-name>
<param-value>org.springframework.web.context.WebApplicationContext.ROOT</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
...省略</web-app>标签...
原理
a、org.springframework.web.context.ContextLoaderListener类实现了javax.servlet.ServletContextListener接口,所以Tomcat发布Web应用时执行该类contextInitialized(ServletContextEvent event)方法,代码如下:
package org.springframework.web.context;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
// Initialize the root web application context.
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());//初始化root web applicationCotext
}
// Close the root web application context.
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
b、执行ContextLoaderListener类中的initWebApplicationContext(event.getServletContext())方法,源码如下:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// 判断application对象是否已经存放了XmlWebApplicationContext实例
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!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext); // 创建XmlWebApplicationContext
}
if (this.context instanceof ConfigurableWebApplicationContext) {// XmlWebApplicationContext类间接实现了ConfigurableWebApplicationContext接口
// 强制转换为ConfigurableWebApplicationContext类型
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {// cwac未被激活,尚没有加载配置文件
// The context has not yet been refreshed -> provide services such as setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);// 加载配置文件
}
}
// 将XmlWebApplicationContext实例保存至application内置对象
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;// 返回XmlWebApplicationContext实例对象
} catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
} catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
ContextLoaderListener类中的configureAndRefreshWebApplicationContext(cwac, servletContext),源码如下:
rotected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value -> assign a more useful id based on available information
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
if (idParam != null) {
wac.setId(idParam);
} else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc); //为wac绑定ServletContext对象
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM); //获取web.xml配置文件中context-param标签key为contextConfigLocation的value值
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
// The wac environment's #initPropertySources will be called in any case when the context is refreshed; do it eagerly here to ensure servlet property sources are in place for use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac);
wac.refresh();
}
d、由于org.springframework.web.servlet.DispatcherServlet配置了load-on-startup,所以Tomcat发布Web应用时依次执行init方法—>initServletBean()方法—>执行initWebApplicationContext()方法,代码如下:
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one has been registered in the servlet context. If one exists, it is assumed that the parent context (if any) has already been set and that the user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);// 创建WebApplicationContext对象
}
if (!this.refreshEventReceived) {// refreshEventReceived全局变量为false
// Either the context is not a ConfigurableApplicationContext with refresh support or the context injected at construction time had already been refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
e、执行findWebApplicationContext()方法,源码如下:
protected WebApplicationContext findWebApplicationContext() {
String attrName = getContextAttribute();// 获取web.xml配置文件中配置DispatcherServlet 时所配置的param-name标签key为contextAttribute的value值,即org.springframework.web.context.WebApplicationContext.ROOT
if (attrName == null) {
return null;
}
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);// 获取application内置对象中保存的XmlWebApplicationContext实例
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
}
return wac;
}
f、执行WebApplicationContextUtils类getWebApplicationContext(getServletContext(), attrName)方法,源码如下:
public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
Assert.notNull(sc, "ServletContext must not be null");
Object attr = sc.getAttribute(attrName); // 获取application内置对象中保存的XmlWebApplicationContext实例
if (attr == null) {
return null;
}
if (attr instanceof RuntimeException) {
throw (RuntimeException) attr;
}
if (attr instanceof Error) {
throw (Error) attr;
}
if (attr instanceof Exception) {
throw new IllegalStateException((Exception) attr);
}
if (!(attr instanceof WebApplicationContext)) {
throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);
}
return (WebApplicationContext) attr;
}