1,Spring搭建的web项目启动首先会加载的webapp/WEB-INF/web.xml文件。其中配置:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
该配置仅看名称就知道它是Spring容器启动的核心,上下文加载监听器。
进入该类方法的initWebApplicationContext()方法
//删除一些日志代码以及cache块
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
//检查web.xml文件是否配置多个ContextLoader
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException();
}
try {
if (this.context == null) {
//创建webIOC容器。查看web.xml文件是否配置了contextClass属性,如有则创建指定的容器,否则采用默认的ContextLoader.properties中的XmlWebApplicationContext容器,通过反射构造创建IOC容器
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
//此时容器还没有refreshed。设置父容器,设置容器的ID等。
if (cwac.getParent() == null) {
//加载web.xml文件是否配置了locatorFactorySelector属性
//加载web.xml文件是否配置parentContextKey属性
//如配置了parentContextKey属性,
//创建BeanFactoryLocator对象 如果locatorFactorySelector属性为空。默认加载classpath*:beanRefContext.xml,
//根据BeanFactoryLocator.useBeanFactory()获取父容器
//如为配置parentContextKey则返回null
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
//*********最重要的部分在这里。它是容器刷新的关键方法。*********
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
//在servletContext中添加容器已经初始化标识
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
return this.context;
}
}
进入configureAndRefreshWebApplicationContext()方法,删除设置ID简单的一些代码
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
//设置容器资源路径,通过web.xml配置contextConfigLocation加载的资源路径
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
//创建运行环境,确保servlet属性源,用于以下刷新之前的任何后处理或者初始化操作。
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
//将servletContext资源添加容器环境中
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
//1:获取配置文件中所有配置globalInitializerClasses、contextInitializerClasses属性中的ApplicationContextInitializer.class对象
//2:将所有上述所有的class进行反射构造对象,并添加到集合中并进行排序
//3:循环依次执行ApplicationContextInitializer.initialize()方法
customizeContext(sc, wac);
//刷新容器,加载组件核心方法
wac.refresh();
}
进入AbstractApplicationContext.refresh()方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//准备该上下文进行刷新
/**
* 1,记录刷新开始时间,将上下文设置未关闭,已开启状态
* 2.在上下文环境中初始化任何占位符属性源,从serveltContext获取配置文件属性
* 3.校验所有的properties属性是否可以正常的解析
* 4.初始化早起发布应用事件
*/
prepareRefresh();
//通知子类刷新内部工厂
/**
* 1.首先执行refreshBeanFactory()方法,判断是否存在beanfactory 如存在销毁以及关闭
* 2.创建DefaultListableBeanFactory对象,并设置序列号ID,设置是否允许重写BeanDefinition,是否允许循环依赖。
* 3.加载BeanDefinition,具体执行AbstractRefreshableApplicationContext.loadBeanDefinitions(beanfactory)方法,
* 以XmlWebApplicationContext为例子。
* 1.创建XmlBeanDefinitionReader对象,设置环境、资源加载者、添加解析实体(META-INF/spring.schemas)
* 2.执行XmlWebApplicationContext。initBeanDefinitionReader(beanDefinitionReader)空方法,子类重写,提供了一个扩展功能
* 3.解析配置文件bean元素,并注册为beanDefinition信息,保存在缓存中。
*/
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
/** 配置工厂上下文标准特征 如上下文的后置处理器
* 1:为beanFactory设置classLoader、SPEL表达解析器、添加属性编辑注册器
* 2:添加ApplicationContextAwareProcessor后置处理器,
*/
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}