Spring bean加载过程以及循环依赖问题
准备
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Person person = context.getBean("person", Person.class);
通过加载xml得到Spring应用上下文
,随后getBean
public class AbstractApplicationContext{
@Override
public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name, requiredType);
}
}
在ClassPathXmlApplicationContext
重载的构造方法中刷新了容器(refresh()
)–后加载bean覆盖先前的bean。其中执行了刷新beanFactory(refreshBeanFactory()
)得到了beanFactory
bean的加载
1、首先别名转换优先
2、从缓存中获取bean的单例
三级缓存中获取(allowEarlyReference
是否允许循环依赖)
为什么会有三级?
实际上单线程下面对循环依赖的问题,一个map是可以解决问题的,也就是给这个“死循环”提供一个出口,但是在多线程下,就会容易造成创建完毕的bean和未完成初始化的bean(刚好完成构造器注入未完成其他,如 setter 注入 的 bean)混合的问题。
为什么不能两级?
会存在代理对象的问题,从三级(singletonFactories
)中返回 有/无 代理的bean
/** 保存 BeanName 和创建 bean 实例之间的关系 bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 保存 BeanName 和创建 bean 实例的工厂之间的关系 bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** 保存 BeanName 和创建 bean 实例之间的关系 bean name --> bean instance */
/** 与 singletonObjects 不同的是当一个单例 bean 被放到里面后,那么在 bean 在创建过程中,就可以通过 getBean 方法获取到,可以用来检测循环引用。 **/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 尝试从一级缓存获取实例
Object singletonObject = this.singletonObjects.get(beanName);
//一级缓存不存在执行二级
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 若该 bean 正在加载则不处理
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 存入到二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
//删除三级缓存中的bean
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
3、从缓存中获取不到bean,判断工厂(parentBeanFactory
)中是否含有当前 Bean 的定义
4、获取不到bean直接创建
缓存中没有,那就当场构建一个 bean 出来,可以看到 getSingleton(String beanName, ObjectFactory)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 记录加载状态,,以便对循环依赖进行检测
beforeSingletonCreation(beanName);
singletonObject = singletonFactory.getObject();
// 移除加载状态
afterSingletonCreation(beanName);
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
构建 ObjectFactory
,其实是在创建一个单例 Bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 对 JDK8 lambda 表达式熟悉的小伙伴就不会陌生了
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
// 划重点了
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
创建bean
-
createBean
–>首先判断需要创建的bean是否可以被实例化,这个类是否可以通过类装载器来载入
-->用 BeanPostProcessors
返回代理来替代真正的实例(如果 Bean 配置了 PostProcessor
,那么这里返回的是一个代理)
doCreateBean
-->实例化
-->检测循环依赖,是否需要提早初始化(只能解决单例Bean)
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//添加到三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
1、RootBeanDefinition 是不是单例,如果是单例先移除缓存
2、实例化 bean,将 RootBeanDefinition 转换为 BeanWrapper
3、使用 MergedBeanDefinitionPostProcessor,Autowired注解 就是通过此方法实现类型的预解析;
4、解决循环依赖问题
5、在 populateBean() 中填充属性,配置在 XML 中的各种属性
6、注册到 DisposableBean 中
7、完成创建并返回 Bean 的实例
三级缓存问题