我们在使用Spring+SpringMVC开发项目中,web.xml中一般的配置如下:

1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> 3 <!-- 加载spring配置 4 默认查找的配置文件位置是:WEB-INF/applicationContext.xml。 5 可通过下面参数指定文件位置--> 6 <context-param> 7 <param-name>contextConfigLocation</param-name> 8 <param-value> 9 classpath:applicationContext.xml 10 </param-value> 11 </context-param> 12 13 <filter> 14 <filter-name>CorsFilter</filter-name> 15 <filter-class>com.filter.CORSFilter</filter-class> 16 </filter> 17 <filter-mapping> 18 <filter-name>CorsFilter</filter-name> 19 <url-pattern>/*</url-pattern> 20 </filter-mapping> 21 22 <listener> 23 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 24 </listener> 25 26 <servlet> 27 <servlet-name>spring-mvc</servlet-name> 28 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 29 <!-- spring mvc 默认加载的配置文件为/WEB-INF/[servlet-name]-servlet.xml,也可通过以下参数指定 --> 30 <!-- <init-param> 31 <param-name>contextConfigLocation</param-name> 32 <param-value>/WEB-INF/spring-mvc-servlet.xml</param-value> 33 </init-param> --> 34 <!-- load-on-startup设置为1,表示项目启动时加载 --> 35 <load-on-startup>1</load-on-startup> 36 </servlet> 37 </web-app>
那么Listener中的contextInitialized方法是什么时候被调用呢?答案就在org.apache.catalina.core.StandardContext类的startInternal方法中
1 //org.apache.catalina.core.StandardContext 2 @Override 3 protected synchronized void startInternal() throws LifecycleException { 4 //省略部分代码,只列出关键代码 5 // Configure and call application event listeners 6 if (ok) { 7 if (!listenerStart()) { 8 log.error(sm.getString("standardContext.listenerFail")); 9 ok = false; 10 } 11 } 12 13 try { 14 // Start manager 15 Manager manager = getManagerInternal(); 16 if ((manager != null) && (manager instanceof Lifecycle)) { 17 ((Lifecycle) getManager()).start(); 18 } 19 } catch(Exception e) { 20 log.error(sm.getString("standardContext.managerFail"), e); 21 ok = false; 22 } 23 24 // Configure and call application filters 25 if (ok) { 26 if (!filterStart()) { 27 log.error(sm.getString("standardContext.filterFail")); 28 ok = false; 29 } 30 } 31 32 // Load and initialize all "load on startup" servlets 33 if (ok) { 34 if (!loadOnStartup(findChildren())){ 35 log.error(sm.getString("standardContext.servletFail")); 36 ok = false; 37 } 38 }
第7行执行触发listener事件,listenerStart()方法中有listener.contextInitialized(event)语句,直接调用listener的contextInitialized方法。
第27行会执行了filter的init方法,具体细节请参照tomcat源码,在此不在详细赘述。
第34行,如果在web.xml中servlet标签指定了<load-on-startup>1</load-on-startup>(值大于0即可),会执行servlet的实例化,然后调用servlet的int(ServletConfig config)。
由此也可指定在Tomcat启动时,这三者调用的先后顺序为listener-->filter-->servlet。
注:StandardContext类的startInternal方法会在Tomcat启动时调用。