如果你接触的技术够新,你会发现,原本以前学习web工程时,每个工程的WEB-INF下面的web.xml似乎不见了。
实话说,技术本来更新换代就比较快,有些人甚至都不知道web.xml是做什么的它就被湮没在历史的洪流中了。
For Example
比如,以下是一个web.xml的例子
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<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-app>
作用-是对ServletContext进行补充
首先,tomcat等容器启动时(这里以tomcat为例),Servlet容器也随之启动。
然后:
①它会先去读取server.xml,启动里面配置的web应用,并为每个应用创建一个“全局上下文环境(ServletContext)”。
②容器启动时,加载web.xml。web.xml的作用就是对ServletContext进行补充。里面可以为每个工程配置Filter、Listener、Servlet。
因此,我们需要明白的一点是,web.xml并不是必须有。
加载顺序
web.xml中大致会有这么几个主要的标签:
1.<context-param>
2.<listener>
3.<filter>
4.<servlet>
加载的顺序为:
context-param -> listener -> filter -> servlet
各个标签的作用
<context-param>
需要加载的配置项。例如这里指定配置文件,多个配置文件以逗号分隔或者换行分隔。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/applicationcontext-*.xml</param-value>
</context-param>
<listener>
使用Spring时,我们通常填入的是:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
这个listener会去加载第一步配置的contextConfigLocation。
这里配置的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());
}
}
1.监听
这个接口只有一个初始化和销毁的方法,监听ServletContext的状态。ServletContext属于容器对象,在用于在容器开启或关闭时触发事件,执行contextInitialized/contextDestroyed
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 );
}
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,调用监听方法。
2.功能
继承的对象ContextLoader中的initWebApplicationContext()方法中会创建WebApplicationContext上下文对象,并将这个对象设置到servletContext中:
①创建IOC容器
initWebApplicationContext调用createWebApplicationContext方法;
–>createWebApplicationContext 调用determineContextClass方法
–> defaultStrategies中加载配置文件:
defaultStrategies.getProperty(WebApplicationContext.class.getName())
ContextLoader 类中有段静态代码:
private static final String DEFAULT_STRATEGIES_PATH = “ContextLoader.properties”;
这个文件中的配置:
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
默认加载的WebApplicationContext是XmlWebApplicationContext,如果不想用默认的,可以在web.xml指定:
<context-param>
<param-name>contextClass</param-name>
<param-value>webApplicationContext类全路径名称</param-value>
<context-param>
②IOC容器配置加载,初始化
这一步主要是调用configureAndRefreshWebApplicationContext。
在上一步中创建了WebApplicationContext对象(ConfigurableApplicationContext类型),也就是创建了IOC容器对象,接着就要给这个对象进行配置参数的设置了。
protected 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);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
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();
}
首先会给WebApplicationContext对象设置ServletContext全局信息,然后读取>contextConfigLocation对应的.xml中的配置信息,例如:
contextConfigLocation classpath*:spring/applicationcontext-*.xml 这些applicationcontext-*.xml配置文件中的信息之后再执行ConfigurableApplicationContext.refresh()方法就会被加载到IOC容器中。未完待续。。。