最近在浏览Spring的源码。对于Spring来讲,Bean的生命周期是很重要的一个知识,了解了生命周期后我们就能对许多概念或者问题有了自己的了解,比如之前自己经常会有疑问的:Spring的Bean的初始化过程是先全都实例化,在进行初始化,还是一个一个完成实例化,初始化的整个过程等问题。
1. 主流程
spring的主流程主要集中在AbstractApplicationContext#refresh()方法上(插一句口,整个Spring的核心是BeanFactory,那这个ApplicationContext又是什么东西呢,通过代码我们实际可以看到,ApplicationContext实际采用的Decorator装饰器模式将BeanFactory封装起来的,这样就可以用于隐藏内部逻辑):
// 同步启动容器或者销毁容器
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 做一些准备,置一些状态位
prepareRefresh();
// 这个是比较重要的一步,加载所有Bean Definition,也就是先加载Bean的定义,这样之后的BeanFactory就能获取诸如getBeanDefination,getBeanNamesForType等方法。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 注册初始化的内容,比如默认的后置处理器PostProcessor等内容
prepareBeanFactory(beanFactory);
try {
// 模板方法,允许在bean实例化前对beanfactory进行修改。
postProcessBeanFactory(beanFactory);
// 实例化BeanFactoryPostProcessor实现类(在Spring中,查找某一个接口或类的实现方式,是通过BeanFactory的findNamesForType等寻找,只要BeanDefination加载完毕即可)。执行BeanFactoryPostProcessor#postProcessBeanFactory方法,因此可见该方法是早于所有Bean的实例化而晚于所有BeanDefinition的加载的
invokeBeanFactoryPostProcessors(beanFactory);
// 实例化BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 为容器初始化Message源,即不同语言的消息体,国际化处理
initMessageSource();
// 初始化应用消息广播器,并放在applicationEventMultcaster的bean中
initApplicationEventMulticaster();
// 执行一些额外的方法,供子类来重写,模板方法的应用
onRefresh();
// 在所有注册的bean中查找Listener bean,注册到消息广播器中
registerListeners();
// 重要,实例化并初始化所有非lazy-init的类
finishBeanFactoryInitialization(beanFactory);
// 做一些结尾的事情,比如清理某些cache,发布ContextRefreshEvent等。
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 如果遇到异常,则销毁beans
destroyBeans();
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
resetCommonCaches();
}
}
}
2. 生命周期流程图

3. 说明
有几点需要说明:
- 加载BeanDefinition和实例化Bean:
Bean的加载实际分为两个主要的步骤的:第一步是全部加载BeanDefinition,也就是所有Bean的定义,依据不同的方式,比如从xml中读取或者读取注解。第二部便是依次实例化和初始化各个Bean。
别看仅仅只有这么两大部,里面却涉及到大量的逻辑与内容。
我们就拿第一步加载中BeanDefinition为例,在AbstractApplicationContext#refresh() obtainFreshBeanFactory()中我们进行的是加载BeanDefinition。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 在这一步我们进行了加载
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
在refreshBeanFactory()中我们进行配置文件的加载并生成BeanDefinition。
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
其中DefaultListableBeanFactory beanFactory = createBeanFactory()中便是加载配置文件的过程。加载的最终结果就是生成了spring的核心容器beanFactory。读取配置文件的过程是一个非常庞大的工作,因为要解析各个标签。比如当我们配置有<context:component-scan/>时,对应的解析规则实际是org.springframework.context.annotation.ComponentScanAnnotationParser类,每一个标签对应了不同的解析类。也有着不同的解析规则,比如引入上了上面的标签时,在parse()的时候,不光会扫描相应的base-package下的类,同时还会将
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source);
也就是将AutowiredAnnotationBeanPostProcessor等后置处理器注入到了beanFactory中,这样就能在createBean的通过后置处理器,能够对@autowired的属性进行注入。
- 循环依赖的问题:
Spring的核心之一DI,在面临循环依赖的时候可能存在些问题,比如类A依赖类B,类B依赖类C,而类C又依赖类A这种问题。对于Spring来讲,循环依赖分为三种情况:
- 构造器循环依赖:无解。
- singleton setter循环依赖:通过提前暴露FactoryObject的方法解决。
- scop=prototype循环依赖:由于prototype作用域的bean,由于没有提前暴露bean的信息,所有自然也无法解决循环依赖的问题。
- 依赖的加载问题:
如果我们类A依赖类B,那么在加载类A的时候的顺序是如何的呢?
首先容器会进行A的实例化,然后在进行属性填入(populate)的时候,发现存在依赖B,而如果此时B还没有实例化的话,则会先去实例化B,并进行注入属性和初始化,完成之后才会继续A的属性填入,之后再完成A的初始化。整个顺序是这个样子的。
4. 参考
- Spring Bean的生命周期
- Spring源码深度解析
网友评论