(如果对于Spring的整体架构和核心技术不了解,建议先看此篇–Spring源码阅读笔记(一):整体架构与核心技术)
基于Spring框架的应用,最主要的亮点就是bean的IoC。而IoC容器的配置、组装由ApplicationContext
完成,那么我们就从这里开始,去探究IoC如何管理到bean对象。
ApplicationContext初始化简要流程
Spring的应用首先需要定义一个ApplicationContext
,此处我们定义的ApplicationContext
为ClassPathXmlApplicationContext
,它的UML图如下:
我们以XML文件配置Spring来进行分析,首先我们的启动类是这样:
public class Application{
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/context.xml");
ctx.start();
}
}
当我们new ClassPathXmlApplicationContext("/context.xml")
的时候,执行ClassPathXmlApplicationContext
构造器,类内部调用:
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
此处调用super(parent)
主要的目的是根据ClassPathXmlApplicationContext
的继承关系构建其上下文环境。 按照继承的顺序依次是DefaultResourceLoader
<– AbstractApplicationContext
<– AbstractRefreshableApplicationContext
<– AbstractRefreshableConfigApplicationContext
<– AbstractXmlApplicationContext
接下来我们依次分析每个类的作用:
DefaultResourceLoader
: 继承此类的目的主要是为了获取类加载器classLoader
以及默认实现根据字符串configLocations
加载具体的Resource
(在ClassPathXml
)。 作为ResourceLoader
的默认实现,它不仅提供了Resource getResource(String location)
的实现,还额外设置了默认的classlLoader–this.classLoader = ClassUtils.getDefaultClassLoader();
.classLoader
: 类加载器的的获取顺序依次为Thread.currentThread().getContextClassLoader()
–>ClassUtils.class.getClassLoader();
–>cl = ClassLoader.getSystemClassLoader();
Resource getResource(String location)
: 此方法的目的要将location
封装为Resource
. 针对不同格式的location
,采用不同的策略(以下也为解析的顺序):
location
以ftp://, http://, file://
等协议开头:通过ProtocolResolver
对象进行解析,在类内部,持有了ProtocolResolver
的集合,可以将不同的协议的解析方式以插件的形式插入.location
以/
开头: 通过静态内部类ClassPathContextResource
包装为Resource
,此类主要使用类或者类加载器的getResourceAsStream(this.path)
方法加载.location
以classpath:
开头: 与/
开头类似,也是通过静态内部类ClassPathContextResource
包装为Resource
, 使用类或者类加载器的getResourceAsStream(this.path)
方法加载- 其他形式: 首先将其当做一个
URL
,所以先通过URL url = new URL(location);return new UrlResource(url)
封装为UrlResource
,如果出错,则处理方式与上同.
AbstractApplicationContext
: 此类的构造器中首先设置了ResourcePatternResolver
为PathMatchingResourcePatternResolver
,这个类的目的是根据输入的configLocations
,寻找对应目录下的资源(包括war://
).AbstractRefreshableApplicationContext
: 主要定义了重新刷新BeanFactory
的方法refreshBeanFactory()
,包括设置是否可重写BeanDefinitions、以及是否允许循环应用;AbstractRefreshableConfigApplicationContext
: 主要讲加载的文件路径中的表达式替换为对应的值,方法为resolvePath(String path)
AbstractXmlApplicationContext
: 主要定义了用于加载BeanDefinitions
的默认实现,相关方法loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
当以上的环境准备好之后,接下来就要进行整个加载流程的核心方法refresh()
:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);
}
// 摧毁已创建的bean避免资源浪费
destroyBeans();
// 重置`active`标识
cancelRefresh(ex);
// 传播异常至调用者
throw ex;
} finally {
resetCommonCaches();
}
}
}
通过refresh()
内部的实现我们大致可以了解整个refresh()
方法担负了整个Spring容器初始化和加载的所有逻辑,包括Bean工厂的初始化、post-processor的注册以及调用、bean的实例化、事件发布等。
下面,我们简要的分析此方法内流程逻辑:
prepareRefresh()
, 为刷新准备上下文,主要设置状态量(是否关闭、是否激活)、记录启动时间、初始化属性资源占位符、校验必填属性是否配置以及初始化用于存储早期应用事件的容器.obtainFreshBeanFactory()
,主要用于获取一个新的BeanFactory,如果BeanFactory已存在,则将其销毁并重建,默认重建的BeanFactory为AbstractRefreshableApplicationContext
;此外,此方法委托其子类从XML中或者基于注解的类中加载BeanDefinition,详细过程请关注后续博客.prepareBeanFactory()
配置BeanFatory使其具有一个上下文的的标准特征,如上下文的类加载器、后处理程序(post-processors,如设置各种感知接口等)postProcessBeanFactory()
在应用上下文内部的BeanFactory初始化结束后对其进行修改,载所有的BeanDefinition
已被加载但还没有实例化bean, 此刻可以注册一些特殊的BeanPostProcessors
,如web应用会注册一些ServletContextAwareProcessor
等invokeBeanFactoryPostProcessors()
调用注册在上下文中的BeanFactoryPostProcessor
,如果给与顺序则按照属性调用,并且一定在单例对象实例化之前调用registerBeanPostProcessors()
实例化并调用所有注册的BeanPostProcessor
,如果有显式的顺序则按照顺序调用;一定在任意的bean实例化之前调用initMessageSource()
初始化MessageSource
,如果当前上下文没有定义则使用其父类的. 如果BeanFactory中不能找到名称为messageSource
的bean, 则默认使用DelegatingMessageSource
initApplicationEventMulticaster()
初始化ApplicationEventMulticaster
,如果上下文没有定义则默认使用SimpleApplicationEventMulticaster
,此类主要用于广播ApplicationEvent
onRefresh()
在一些特定的上下文子类中初始化特定的bean, 如在Webapp的上下文中初始化主题资源;registerListeners()
添加实现了ApplicationListener
的bean作为监听器,它不影响非bean的监听器;它还会使用多播器发布早期的ApplicationEvent
finishBeanFactoryInitialization()
实例化所有非延迟加载的单例,完成bean factory的初始化工作;finishRefresh()
完成上下文的刷新工作,调用LifecycleProcessor
的onFresh()
方法以及发布ContextRefreshedEvent
事件resetCommonCaches()
重置Spring公共的缓存,比较典型的如:ReflectionUtils
,ResolvableType
以及CachedIntrospectionResults
的缓存
至此,整个应用上下文建立成功.