1.背景知识
我用的sprin-boot 2.7版本,这个版本(没查是哪个版本开始的)默认情况下是不会解决循环依赖,而是启动程序会报错,如果需要spring帮我们解决循环依赖,需要加上一个配置spring.main.allow-circular-references=true。spring现在建议通过构造方法注入,这个时候你就不要想解决循环依赖,解决不了,这样的目的就是希望我们自己把循环依赖解决好,如果真出现了循环依赖,要先考虑自己的程序设计是不是又有问题,随着微服务的的普及,基本上是不会出现循环依赖的问题了,如果出现了你得考虑自己打程序的业务、架构是不是有问题。实际上这个循环依赖不是很重要的东西,仅作为了解就行了,分析一下spring的解决思路。
首先spring中没有什么三级缓存的概念,因为getSingleton的时候,查找顺序是:singletonObjects-》
earlySingletonObjects-》singletonFactories。
这三个map就是大家常说的三级缓存:
singletonObjects : 一级缓存 :保存可以使用的单例bean
earlySingletonObjects :二级缓存:保存被循环依赖的bean对象(也可能是bean的代理对象)
singletonFactories: 三级缓存:bean实例化生成对应的ObjectFactory
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within
// full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects
.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory =
this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName,
singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
2.bean创建过程
大致上可以分为以下几个过程:假设现在正在创建的bean是A,beanName就叫a
1)createBeanInstance(beanName, mbd, args)
2)addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
3)populateBean(beanName, mbd, instanceWrapper);
4)exposedObject = initializeBean(beanName, exposedObject, mbd);
5)if (earlySingletonReference != null)
6)addSingleton(beanName, singletonObject);
1)通过反射调用构造方法,产生对象a,这个是a还是个半成品,没有完成依赖注入和初始化。
2)把a的引用加入singletonFactories(三级缓存),key就是a的beanName,value是一个lambda表达式,可以简单成new了一个ObjectFactory的匿名对象,实现了getObject()方法,实现逻辑就是这个getEarlyBeanReference(beanName, mbd, bean),这样调用ObjectFactory.getObject()内部就是执行getEarlyBeanReference(beanName, mbd, bean)
3)依赖注入,如果a依赖的其他bean,其他bean又会执行整个bean的创建过程,结果就是a依赖注入其他的bean完成以后,其他bean必须是已经放入到单例池了。
4)初始化,这个时候如果a对象需要产生代理对象,在applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);里面会循环所有的BeanPostProcessor并执行postProcessAfterInitialization方法,其中有生成代理的BeanPostProcessor,会检查是配置了aop信息。
5)检查这个a是否存在earlySingletonObjects(二级缓存),如果存在(说明这个bean产生了循环依赖),则用earlySingletonObjects中的代理对象替换当前的bean引用
6)把bean的引用存入singletonObjects(一级缓存),同时移除beanName在二级、三级的其他引用。
到此整个bean就算创建完成了,可以使用了。