spring的初始化入口,是一个名叫ContextLoaderListener的监听器类,实现了ServletContextListener接口,继承ContextLoader类
public class ContextLoaderListener extends ContextLoader implements ServletContextListener { public ContextLoaderListener() { } ... public void contextInitialized(ServletContextEvent event) { this.initWebApplicationContext(event.getServletContext()); } .... }
其中,初始化的方法就是contextInitialize,此方法实现自ServletContextListener。ServletContextListener中有两个接口,一个用于初始化容器使用,一个用于容器关闭时使用:
public interface ServletContextListener extends EventListener { default void contextInitialized(ServletContextEvent sce) { } default void contextDestroyed(ServletContextEvent sce) { } }
接着看具体的实现方法initWebApplicationContext方法,此处调用的是父类ContextLoader中的方法:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// 判断容器ServletContext中如果已经创建了WebApplicationContext对象,如果有,就抛出异常
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!");
} else {
....
try {
if(this.context == null) {
// 创建WebApplicationContext对象,即初始化
this.context = this.createWebApplicationContext(servletContext);
}
if(this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
if(!cwac.isActive()) {
if(cwac.getParent() == null) {
ApplicationContext parent = this.loadParentContext(servletContext);
cwac.setParent(parent);
}
this.configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
// 将WebApplicationContext以ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE名字存储到servletContext中
// String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
...
return this.context;
} catch (Error | RuntimeException var8) {
logger.error("Context initialization failed", var8);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);
throw var8;
}
}
}
可以在跟踪创建webApplicationContext的方法,如下
protected WebApplicationContext createWebApplicationContext(ServletContext sc) { Class<?> contextClass = this.determineContextClass(sc); if(!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); } else { return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass); } } protected Class<?> determineContextClass(ServletContext servletContext) { String contextClassName = servletContext.getInitParameter("contextClass"); if(contextClassName != null) { .... } else { contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); ... } } }
defaultStrategies就是读取文件的流对象
static { try { ClassPathResource resource = new ClassPathResource("ContextLoader.properties", ContextLoader.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException var1) { throw new IllegalStateException("Could not load 'ContextLoader.properties': " + var1.getMessage()); } currentContextPerThread = new ConcurrentHashMap(1); }
其中,ContextLoader.properties如下内容org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
通过子类XmlWebApplicationContext进行反射初始化WebApplicationContext