通过前面的学习,我们已经了解了spring的初级容器是如何初始化了,但是相比于陌生的XmlBeanFactory而言ApplicationContext显然大家更加的熟悉,在spring高级容器ApplicationContext中,包含了初级容器XmlBeanFactory中所有的东西 。ApplicationContext在初级容器的基础之上,扩展了非常多的高级特性,同时也给我们提供了非常多的功能扩展点,通过这些功能扩展点,我们可以将spring这个框架的功能改造的更加满足于我实际的业务场景。从这一篇开始我们就一起去探索spring的高级容器ApplicationContext是如何初始化的吧。
我们先来看下ApplicationContext简单实用:
可以看到,同样是解析xml文件,如果我使用ApplicationContext来解析的话,也就是将之前的XmlBeanFactory替换成了ApplicationContext的实现类CalssPathXmlApplicationContext,执行的结果和XmlBeanFactory是一样的。ApplicationContext接口的实现类也是比较多的。我们使用ClassPathXmlApplicationContext作为ApplicationContext初始化源码分析的入口。
通过ClassPathXmlApplicationContext的名称,我们可以知道它是从classpath路径加载和解析applicationContext.xml的。
我们进去ClassPathXmlApplicationContext 方法看下:
可以看到,在classPathXmlApplicationContextd的构造方法中,首先会把xml文件名称封装成一个String类型的数组,然后带上参数refresh的值true和parent值null,继续调用ClassPathXmlApplicationContext另外的一个重载构造方法。
我们到这个ClassPathXmlApplicationContext的重载构造方法中看下:
可以看到,首先用super方法调用父类的构造器,我们层层的跟到父类AbstractApplicationContext,发现这个里面有两个方法:
我们到this() 方法中看下:
这里应该是初始化一个成员变量resourcePatternResolver,那getResourcePatternResolver方法能获取到什么呢?我们继续进去看下:
可以看到,成员变量resourcePatternResolver 被初始化了PathMatchingResourcePatternResolver类型,根据名称我们可以推测PathMatchingResourcePatternResolver应该是匹配路径的一个资源解析器,应该是获取xml文件资源的一个组件。
我们在看这个setParent方法:
可以看到往setParent方法中传入了参数parent,我们知道这个parent参数传入的是个null值。
我们在回到ClassPathXmlApplicationContext构造方法的位置:
applicationContext.xml 文件封装为String数组作为参数传入,然后调用方法setConfigLocations。
我们到这个setConfigLocactions方法中看下:
可以看到,在setConfigLocations方法中,通过我们传入的参数locations,构建了一个新的string数组configLocations,用于存放解析后的xml文件路径。
那这个resolvePath会怎么解析呢?我么看一下:
我们到方法resolveRequiredPlaceholders中看下:
也就是,我们传入的xml路径参数path中,如果存在占位符 ${}
,那方法resolveRequiredPlaceholders就可以解析占位符。而且,如果xml的路径中有${}
占位符,但是却没有对应的默认属性值是会报错的。
到现在我们已经看到了,spring会为我们设置进去的xml路径进行一些准备处理,比如解析路径中的一些占位符,但是具体在什么时候加载和解析xml文件呢?
现在,我们再看ClassPathXMLApplicationContext构造方法:
前面我们已经看到,参数refresh的值为true,所以会调用refresh方法,那refresh方法到底是在干什呢?
我们到这个refresh方法中看下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 初始化上下文信息
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 初始化初级容器BeanFactory,并解析xml文件
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 对spring容器beanFactory做一些准备工作
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 空实现,留个子类去拓展实现。用于注册特殊的后置处理器来加载特殊的一些bean
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 执行BeanFactory即Spring容器级别的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 在spring容器中,注册bean的后置处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 在spring容器,初始化消息源MessageSource
initMessageSource();
// Initialize event multicaster for this context.
// spring容器,初始化事件广播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 空实现,留给子类去拓展实现
// 用于在实例化bean之前,做一些其他初始化bean的工作
onRefresh();
// Check for listener beans and register them.
// 初始化spring容器中的各种监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 预先实例化那些非延迟加载的单例bean
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();
}
}
}
可以看到。容器ApplicationContext初始化的核心逻辑都在refresh中,下面的篇符中,我都是围绕则refresh方法来展开的。