下面的代码段摘自web.xml
<
context-param
>
< param-name > webAppRootKey </ param-name >
< param-value > gsports.root </ param-value >
</ context-param >
< listener >
< listener-class > org.springframework.web.context.ContextLoaderListener </ listener-class >
</ listener >
< listener >
< listener-class > org.springframework.web.util.IntrospectorCleanupListener </ listener-class >
</ listener >
< param-name > webAppRootKey </ param-name >
< param-value > gsports.root </ param-value >
</ context-param >
< listener >
< listener-class > org.springframework.web.context.ContextLoaderListener </ listener-class >
</ listener >
< listener >
< listener-class > org.springframework.web.util.IntrospectorCleanupListener </ listener-class >
</ listener >
下面我们来了解一下ContextLoaderListener类到底做了什么
ContextLoadListener继承ServletContextListener,并保留了一个ContextLoader引用(contextLoader),在实现ServletContextListener的初始化方法contextInitialized是实例化了contextLoader,如下程序段
public
void
contextInitialized(ServletContextEvent event)
...
{
this.contextLoader = createContextLoader();
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
this.contextLoader = createContextLoader();
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
下面我看一下ContextLoader做了什么?在ContextLoader中提供了如下方法
public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
throws IllegalStateException, BeansException;
该方法的作用是:根据配置的
contextClass
和
contextConfigLocation
,初始化
web
应用的上下文(
Application Context
),并返回一个
WebApplicationContext
对象,我们看一下下面的类层次图,发现
WebApplicationContext
其实就是一个
ApplictionContext
,或者就是一个
BeanFactory
。
<
context-param
>
< param-name > contextConfigLocation </ param-name >
< param-value >
classpath:org/codehaus/xfire/spring/xfire.xml
/WEB-INF/dataAccessContext-local.xml
/WEB-INF/applicationContext.xml
/WEB-INF/xfire-servlet.xml
</ param-value >
</ context-param >
< param-name > contextConfigLocation </ param-name >
< param-value >
classpath:org/codehaus/xfire/spring/xfire.xml
/WEB-INF/dataAccessContext-local.xml
/WEB-INF/applicationContext.xml
/WEB-INF/xfire-servlet.xml
</ param-value >
</ context-param >
到底这个WebApplicationContext对象是如何创建的呢?如下面的程序段说明如何创建WebApplicationContext,大体上如下过程:1,借助于BeanUtils.instantiateClass()方法实例化WebApplicationContext,2,设置父ApplicationContext,3,设置ServletContext,4,调用refresh方法加载全部bean对象。
/** */
/**
* Instantiate the root WebApplicationContext for this loader, either the
* default context class or a custom context class if specified.
* <p>This implementation expects custom contexts to implement
* ConfigurableWebApplicationContext. Can be overridden in subclasses.
* @param servletContext current servlet context
* @param parent the parent ApplicationContext to use, or <code>null</code> if none
* @return the root WebApplicationContext
* @throws BeansException if the context couldn't be initialized
* @see ConfigurableWebApplicationContext
*/
protected WebApplicationContext createWebApplicationContext(
ServletContext servletContext, ApplicationContext parent) throws BeansException ... {
Class contextClass = determineContextClass(servletContext);
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) ...{
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setParent(parent);
wac.setServletContext(servletContext);
String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocation != null) ...{
wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,
ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
wac.refresh();
return wac;
}
* Instantiate the root WebApplicationContext for this loader, either the
* default context class or a custom context class if specified.
* <p>This implementation expects custom contexts to implement
* ConfigurableWebApplicationContext. Can be overridden in subclasses.
* @param servletContext current servlet context
* @param parent the parent ApplicationContext to use, or <code>null</code> if none
* @return the root WebApplicationContext
* @throws BeansException if the context couldn't be initialized
* @see ConfigurableWebApplicationContext
*/
protected WebApplicationContext createWebApplicationContext(
ServletContext servletContext, ApplicationContext parent) throws BeansException ... {
Class contextClass = determineContextClass(servletContext);
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) ...{
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setParent(parent);
wac.setServletContext(servletContext);
String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocation != null) ...{
wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,
ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
wac.refresh();
return wac;
}
好的下面来总结一下,从ContextLoaderListener->ContextLoader->WebApplicationContext的初始化过程。如下时序图。
最后,ContextLoader调用WebApplicationContext的refresh方法,加载受控对象。
题外话,我们了解一下ContextLoader是如何创建并初始化WebApplicationContext的,首先我们了解一下ContextLoader.properties
ContextLoader.properties
# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
org.springframework.web.context.WebApplicationContext = org.springframework.web.context.support.XmlWebApplicationContext
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
org.springframework.web.context.WebApplicationContext = org.springframework.web.context.support.XmlWebApplicationContext
ContextLoader读取资源文件,如果web.xml中没有配置上下文类contextClass,则读取默认的,即org.springframework.web.context.support.XmlWebApplicationContext。由下图可以看出XmlWebApplicationContext的类层次图。
至于创建XmlWebApplicationContext的细节,这里就不做叙述了。