一、背景
我们都知道Spring可以通过xml,或者解析我们的注解,通过扫描所有资源文件,从而将所有匹配到的资源封装成为一个BeanDefinition注册到我们的BeanFactory中。
此时,Spring已经知道了所有我们想要注册到容器中的BeanDefinition,下一步就是将BeanDefinition实例化,这样才能提供出来给我们使用。
二、Spring中Bean的实例化
我们发现Spring整个加载过程都在AbstractApplicationContext.refresh()中去完成。
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
* ClassPathXmlApplicationContext:1.新建BeanFactory,2.解析xml,3.封装成BeanDefintion对象
* AnnotationConfigApplicationContext: 获取GenericApplicationContext中的beanFactory
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 为BeanFactory进行必要的准备工作
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 进行额外的后置处理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 执行1.BeanDefinitionResgistryPostProcessor、2.BeanFactoryPostProcessor的回调
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 实例化所有实现了BeanPostProcessor接口的类并注册到容器中去
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.
//1.bean实例化,2.ioc 3.注解支持 4.BeanPostProssor执行 5.AOP入口
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();
}
}
我们着重关注一下finishBeanFactoryInitialization方法,它是Spring实例化的入口方法。
- 获取BeanFactory中所有的beanDefinition名称
- 合并RootBeanDefinition
- 非抽象的,单例的,非懒加载的就实例化
- 是否实现了FactoryBean接口,如果是加一个&前缀调用内部的getObject,否则直接获取
- 首先尝试从缓存中获取getSingleton(beanName),(首次获取必然获取不到)接着进入创建方法
- 单例创建之前的操作:加入到正在创建的一个set集合中singletonsCurrentlyInCreation
- 调到外部的匿名类中的实例化方法,如果有值已经创建成功singletonFactory.getObject();
- 调到doCreateBean创建实例BeanWrapper
- 允许早期引用加入单例工厂直接返回这个bean的引用。addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
- 填充属性的值populateBean
- initializeBean
三、Spring容器如何解决循环依赖
什么是循环依赖
循环依赖就是循环引用,就是两个或多个 bean 相互之间的持有对方,比如 CircleA 引用 C ircleB , CircleB 引用 CircleC, CircleC 引用 CircleA,则它们最终反映为一个环。
@Component
public class CircleClassA {
public CircleClassA() {
System.out.println("====CircleClassA====");
}
}
@Component
public class CircleClassB {
public CircleClassB() {
System.out.println("====CircleClassB====");
}
}
首先我们需要明确的一点是:Spring只会处理上述类型的循环依赖(单例,非构造函数注入)其它情况直接报错。
Spring在处理Bean实例化的过程中是如何解决循环依赖的呢?我们需要着重关注如下3个Map。
singletonObjects
earlySingletonObjects
singletonFactories
具体步骤如下:
- CircleClassA 在实例化的时候 首先从缓存中获取不到,然后进入创建方法,接着将CircleClassA加入到singletonsCurrentlyInCreation中,并在singletonFactories加入一个getEarlyBeanReference,表示当前CircleClassA正在创建中。
- 当CircleClassA填充属性的值populateBean时,发现依赖了CircleClassB,触发CircleClassB的实例化。
- 实例化CircleClassB,首先从缓存中获取不到,然后进入创建方法,接着将CircleClassB加入到singletonsCurrentlyInCreation中,并在singletonFactories加入一个getEarlyBeanReference,表示当前CircleClassB正在创建中。
- 当CircleClassB填充属性的值populateBean时,发现依赖了CircleClassA,触发CircleClassA的实例化。
- 再次进入CircleClassA 的实例化方法,此时虽然singletonObjects中获取不到CircleClassA,但是检测到CircleClassA存在早期暴露的实例因此尝试从earlySingletonObjects中获取,首次调用获取不到从singletonFactories中获取,取到之后将CircleClassA放入earlySingletonObjects,并提供给CircleClassB填充属性的值populateBean时使用。(此时的CircleClassA只是个引用的地址,实际上并不是一个完整的CircleClassA)。
- 此时CircleClassB已经完成了(内部依赖的CircleClassA是个不完整的实例)并提供给CircleClassA填充属性的值populateBean时使用。CircleClassA完成了CircleClassB的注入,它变成了一个完整的实例。
- 又由于CircleClassB中引用了CircleClassA的一个地址。所以它也同时变成了一个完整的。
- 实例化完成之后删除早期引用map,并放入单例map中缓存singletonObjects。
程序员的核心竞争力其实还是技术,因此对技术还是要不断的学习,关注 “IT巅峰技术” 公众号 ,该公众号内容定位:中高级开发、架构师、中层管理人员等中高端岗位服务的,除了技术交流外还有很多架构思想和实战案例。
作者是 《 消息中间件 RocketMQ 技术内幕》 一书作者,同时也是 “RocketMQ上海社区”联合创始人,曾就职于拼多多、德邦等公司,现任上市快递公司架构负责人,主要负责开发框架的搭建、中间件相关技术的二次开发和运维管理、混合云及基础服务平台的建设。