首先回归一下web.xml的常用配置,看一个示例:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationcontext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/springmvc-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
了解web.xml的作用之前必须要了解web容器(也称为是servlet容器)这个概念,常用的web容器有Tomcat、Jetty、JBoss等。
使用web容器,就不得不清楚什么是ServletContext。ServletContext中的信息都是由容器提供的,在web容器启动时,它作为为公共环境容器存放公共信息,为各个Servlet提供信息,也可以作为各个Servlet之间通信的桥梁。
将应用部署到web容器中,启动web容器后,web容器会读取web.xml中的配置信息,对ServletContext进行信息补充。
好了,回到本文主题。
web.xml中的配置文件中ContextLoaderListener作为监听器,会监听web容器相关事件,在web容器启动或者关闭时触发执行响应程序。具体地,ContextLoaderListener继承ContextLoader类并实现了ServletContextListener接口。
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
public void contextInitialized(ServletContextEvent event) {
this.initWebApplicationContext(event.getServletContext());
}
public void contextDestroyed(ServletContextEvent event) {
this.closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
ServletContextListener接口中只有初始化和销毁的两个方法::
public interface ServletContextListener extends EventListener {
/**
** Notification that the web application initialization
** process is starting.
** All ServletContextListeners are notified of context
** initialization before any filter or servlet in the web
** application is initialized.
*/
public void contextInitialized ( ServletContextEvent sce );
/**
** Notification that the servlet context is about to be shut down.
** All servlets and filters have been destroy()ed before any
** ServletContextListeners are notified of context
** destruction.
*/
public void contextDestroyed ( ServletContextEvent sce );
}
也就是监听ServletContext的状态,ServletContext属于容器对象,在用于在容器开启或关闭时触发事件,执行contextInitialized/contextDestroyed 。如果想了解程序执行原由可以先了解事件监听设计模式。查阅Tomcat源码,tomcat触发ServletContext初始化监听事件的源码如下:
...(部分略)
Object instances[] = getApplicationLifecycleListeners();
for (int i = 0; i < instances.length; i++) {
if (!(instances[i] instanceof ServletContextListener))
continue;
ServletContextListener listener = (ServletContextListener) instances[i];
try {
if (noPluggabilityListeners.contains(listener)) {
listener.contextInitialized(tldEvent);
} else {
listener.contextInitialized(event);
}
} catch (Throwable t) {
}
}
...(部分略)
也就是,遍历所有ServletContextListener,调用监听方法。
关于功能主要看initWebApplicationContext()方法,ContextLoaderListener继承ContextLoader,ContextLoader中的initWebApplicationContext()方法中会创建WebApplicationContext上下文对象,并将这个对象设置到servletContext中:
ContextLoaderListener加载过程:
initWebApplicationContext调用createWebApplicationContext方法;
-->createWebApplicationContext 调用determineContextClass方法
--> defaultStrategies中加载配置文件:
defaultStrategies.getProperty(WebApplicationContext.class.getName())
ContextLoader 类中有段静态代码:
static {
try {
ClassPathResource resource = new ClassPathResource(
"ContextLoader.properties", ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
} catch (IOException ex) {
throw new IllegalStateException(
"Could not load ‘ContextLoader.properties‘: "
+ ex.getMessage());
}
currentContextPerThread = new ConcurrentHashMap(1);
}
ContextLoader.properties 文件内容如下:
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
可知,默认加载的WebApplicationContext是XmlWebApplicationContext
题外话,如果你不想使用默认的,在web.xml中配置contextClass即可
protected Class<?> determineContextClass(ServletContext servletContext) {
String contextClassName = servletContext.getInitParameter("contextClass");
if(contextClassName != null) {
try {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
...(略)
也就是这种形式:
<context-param>
<param-name>contextClass</param-name>
<param-value>webApplicationContext类全路径名称</param-value>
<context-param>
到org.springframework.web.context.support包下查询webApplicationContext。
这一步主要是调用configureAndRefreshWebApplicationContext,可知在上一步中创建了WebApplicationContext对象(ConfigurableApplicationContext类型),也就是创建了IOC容器对象,接着就要给这个对象进行配置参数的设置了。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
String configLocationParam;
if(ObjectUtils.identityToString(wac).equals(wac.getId())) {
configLocationParam = sc.getInitParameter("contextId");
if(configLocationParam != null) {
wac.setId(configLocationParam);
} else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc);
configLocationParam = sc.getInitParameter("contextConfigLocation");
if(configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
ConfigurableEnvironment env = wac.getEnvironment();
if(env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment)env).initPropertySources(sc, (ServletConfig)null);
}
this.customizeContext(sc, wac);
wac.refresh();
}
可知,首先会给WebApplicationContext对象设置ServletContext全局信息,然后读取><param-name>contextConfigLocation</param-name>对应的.xml中的配置信息,例如:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationcontext-*.xml</param-value>
</context-param>
这些applicationcontext-*.xml配置文件中的信息之后再执行ConfigurableApplicationContext.refresh()方法就会被加载到IOC容器中。
IOC容器的初始化过程,参考下一篇文章。
springmvc web.xml配置之ContextLoaderListener
原文:https://www.cnblogs.com/chenjunjie12321/p/9357534.html