Bean的循环依赖

问题

public class A {
    private B b;
}

public class B {
    private A a;
}
/**********************/
<bean id="beanA" class="xyz.coolblog.BeanA">
    <property name="beanB" ref="beanB"/>
</bean>
<bean id="beanB" class="xyz.coolblog.BeanB">
    <property name="beanA" ref="beanA"/>
</bean>

Bean的实例化分三步

 createBeanInstance实例化 -> populateBean 填充属性 -> initializeBean初始化

如何解决

为了解决单例的循环依赖问题,使用了三级缓存,递归调用发现Bean还在创建中即为循环依赖

/** 一级缓存:用于存放完全初始化好的 bean **/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** 二级缓存:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖 */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

/** 三级级缓存:存放 bean 工厂对象,用于解决循环依赖 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/**
bean 的获取过程:先从一级获取,失败再从二级、三级里面获取

创建中状态:是指对象已经 new 出来了但是所有的属性均为 null 等待被 init
*/

比如:1) A创建过程中需要B,于是A先放入到三级缓存中,去实例化B
2) B实例化时需要A,于是B先查一级缓存,没有,在查二级缓存,还是没有,再查三级缓存,找到啦!
3)然后三级缓存里面这个A放到二级缓存中,并删除三级缓存里面的A
4) B初始化完毕,放入到一级缓存中(此时B中A还再创建中状态)
5)然后接着创建A,此时B已经创建结束,直接从一级缓存中拿到B,然后完成创建,并将自己放到一级缓
存里面

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) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

一句话:先让最底层对象完成初始化,通过三级缓存与二级缓存提前曝光创建中的 Bean,让其他 Bean 率先完成初始化。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容