源码分析:Spring如何解决单例Bean的循环依赖?
2021.05.17 16:41浏览量:191简介:Spring通过ObjectFactory提前暴漏一个创建中的Bean(BeanWrapper).
假设Bean为A,第一次对A进行依赖查找时是查不到beanName对应实例的,因为
● singletonObjects:不存在A对应元素,A完全初始化之后才会放进去。
● singletonsCurrentlyInCreation:也不存在A对应元素!用以标识创建中的状态!
看下getSingleton(String beanName,boolean allowEarlyReference);
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//返回提前暴漏的Bean。之所以能解决循环依赖,就是其他Bean依赖当前BeanA的时候singletonFactories返回了A的beanName关联的Objectfactory,而这个ObjectFactory可以提前暴漏未完全初始化的Bean A实例,其实是一个BeanWrapper对象,尚未填充属性和初始化Bean。
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
所以shareInstance返回null,忽略一些无关代码,于是执行到getSingleton(String,ObjectFactory<?>)代码.
//AbstractBeanFactory.java
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
....
Object sharedInstance = getSingleton(beanName, true);
.....
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
.....
return bean;
}
通过代码细节看到singleObjects中找不到beanName对应的实例,但是后边会根据singletonFactory.getObject()来查找Bean。singletonFactory就是传进来的包含createBean的lambda表达式。但在创建之前需要做一些前置准备,也就是执行beforeSingletonCreation(String beanName);此方法中执行的操作就是“标志A这个Bean在创建中”。即singletonsCurrentlyInCreation.add(String BeanName)方法。
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
//DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
....
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
...
//this.singletonsCurrentlyInCreation.add(beanName)
beforeSingletonCreation(beanName);
...
try {
//AbstractAutowireCapableBeanFactory#createBean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}catch(...){}
finally{
...
//this.singletonsCurrentlyInCreation.remove(beanName)
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 实际执行的是
// protected void addSingleton(String beanName, Object singletonObject) {
// synchronized (this.singletonObjects) {
// this.singletonObjects.put(beanName, singletonObject);
// this.singletonFactories.remove(beanName);
// this.earlySingletonObjects.remove(beanName);
// this.registeredSingletons.add(beanName);
// }
// }
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
创建完Bean以后,即createBean方法执行完毕之后,在finally块中就删除掉Bean A创建中的标识了,即:
afterSingletonCreation(beanName);
实际就是this.singletonsCurrentlyInCreation.remove(beanName);这一行代码起了作用。
Bean A创建完了,但还需要执行下边操作:
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
这个操作的作用是更新Bean在Spring容器中的缓存状态。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//缓存Bean
this.singletonObjects.put(beanName, singletonObject);
//删除beanName关联的用以提前暴漏Bean的ObjectFactory
this.singletonFactories.remove(beanName);
//删除早期暴漏bean缓存标识
this.earlySingletonObjects.remove(beanName);
//注册为单例Bean
this.registeredSingletons.add(beanName);
}
}
在createBean中执行Bean A实例化的主要就是doCreateBean。
这个方法里判断:
- 单例Bean
- 允许循环依赖
- 正在创建中
能满足这个三个条件,则Spring会认为这个此时A是需要提前暴漏的单例Bean。因为只有提前暴漏才能解决循环依赖的问题。那么如何提前暴漏单例Bean A呢?
其实就是给A关联一个ObjectFactory对象。然后再进行Bean的初始化进程即populateBean和initializeBean,最后返回初始化之后的Bean。
那么代码getSingleton(String beanName, ObjectFactory<?> singletonFactory)中singletonFactory.getObject();这一行就返回了。
拿到了createBean之后的Bean A实例对象,相当于Bean A已经创建完成了,那么执行finally里的afterSingletonCreation方法。从singletonsCurrentlyInCreation中删除beanName,毕竟Bean已经创建结束了,就是前边已经提到的finally块中的afterSingletonCreation(beanName);这行代码。
但是本文核心问题来了,如果Bean A依赖了Bean C,那么createBean方法执行时必然会去依赖查找Bean C,而Bean C同样执行getBean方法来实例化和初始化,在这个过程中Bean C如果依赖了Bean A,就形成了A–C—A这样的循环依赖。Bean A虽然还没初始化完成,但是在getBean查找Bean C之前却提前暴漏了自己。也就是 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));这行代码。
//AbstractAutowireCapableBeanFactory
protected Object doCreateBean(
final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
.........
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure =
(mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName
+"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}catch(...){...}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
.........
}
}
return exposedObject;
}
重点看下提前暴漏都做了啥?
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
/**
* Add the given singleton factory for building the specified singleton
* if necessary.
* <p>To be called for eager registration of singletons, e.g. to be able to
* resolve circular references.
* @param beanName the name of the bean
* @param singletonFactory the factory for the singleton object
*/
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
//关键代码,beanName关联singletonFactory
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
给Bean A关联了一个ObjectFactory,也就是getEarlyBeanReference对应的lambda函数对象。放入了singletonFactories中,当Bean C去查BeanA的时候就可以通过getEarlyBeanReference方法获取exposedObject这个早期bean对象。
/**
* Obtain a reference for early access to the specified bean,
* typically for the purpose of resolving a circular reference.
* @param beanName the name of the bean (for error handling purposes)
* @param mbd the merged bean definition for the bean
* @param bean the raw bean instance
* @return the object to expose as bean reference
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
看下Bean C怎么依赖查Bean A?
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
//如果C来查找A,此时会符合if条件
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//这里C来查A一定查不到,符合下边的if条件
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//C来查A,singletonFactories是有值的
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//调用getEarlyBeanReference返回exposedObject
singletonObject = singletonFactory.getObject();
//全局也只有此处对earlySingletonObjects进行put
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
到这里,基本上已经分析完了关于单例Bean循环依赖的问题,应该还是挺清晰的,总结一下:
Spring通过ObjectFactory提前暴漏一个创建中的Bean(BeanWrapper).给依赖它的Bean使用。让依赖它的Bean的初始化不再需要等待其完全初始化,避免了循环依赖的问题!
————————————————
版权声明:本文为CSDN博主「Jeff.S」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/shengqianfeng/article/details/116495968
发表评论
登录后可评论,请前往 登录 或 注册