1. 循环依赖

1.1. 源码解读

  • 类:DefaultSingletonBeanRegistry
  • 核心集合:singletonObjects、singletonFactories、earlySingletonObjects、registeredSingletons
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects=new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>>singletonFactories=new HashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects=new ConcurrentHashMap<>(16);

/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation=
        Collections.newSetFromMap(new ConcurrentHashMap<>(16));
  • 流程:
    • 检测当前 bean 是否在 singletonObjects 中,在则直接返回缓存好的 bean;不在则检测 是否在 singletonFactories 中,在,则调用其 getObject 方法,返回,并从 singletonFactories 中移除,加入到 earlySingletonObjects 中。
    • 正常创建,beforeSingletonCreation:检测当前 bean 是否在 singletonsCurrentlyInCreation, 如果存在,抛出异常。表示存在构造器循环依赖。如果不存在,则将当前 bean 加入。
    • bean 初始化,分为构造方法初始化、工厂方法初始化和简单初始化。如果是构造方法初 始化,那么递归地获取参数 bean。其他情况不会递归获取 bean。
    • addSingletonFactory:如果当前 bean 不在 singletonObjects 中,则将当前 bean 加入到 singletonFactories 中,并从 earlySingletonObjects 中移除。
    • 调用用户初始化方法,比如 BeanPostProcesser、InitializingBean、init-method,有可能 返回代理后的 bean。
    • 检测循环依赖,如果当前 bean 在 singletonObjects 中,则判断当前 bean(current bean) 与 singletonObjects 中的 bean(cached bean)是否是同一个,如果不是,那么说明当前 bean 是被代理过的,由于依赖当前 bean 的 bean 持有的是对 cached bean 的引用,这是不被允许的,所以会抛出 BeanCurrentlyInCreationException 异常。
    • afterSingletonCreation:将当前 bean 从 singletonsCurrentlyInCreation 中删除
    • addSingleton: 将当前bean加入到 singletonObjects,然后从singletonFactories, earlySingletonObjects中移除,结束

1.2. 通过构造器注入构成的循环依赖,无法解决,只能抛出异常:BeanCurrentlyInCreationException

  1. Spring 容器创建单例“A” Bean,首先检测 singletonFactories 是否包含 A,发现没有,于是正常创建,然后检测 A 是否包含在 singletonsCurrentlyInCreation中,没有,则将 A 放入。 构造方法初始化时需要 B 实例(A 尚未放入到 singletonFactories 中),于是调用了 getBean(B) 方法、
  2. Spring 容器创建单例“B” Bean,首先检测 singletonFactories 是否包含 B,发现没有,于是正常创建,然后检测 B 是否包含在 singletonsCurrentlyInCreation中,没有,则将 B 放入。 构造方法初始化时需要 C 实例(B 尚未放入到 singletonFactories 中),于是调用了 getBean(C) 方法、
  3. Spring 容器创建单例“C” Bean,首先检测 singletonFactories 是否包含 C,发现没有,于是正常创建,然后检测 C 是否包含在 singletonsCurrentlyInCreation中,没有,则将 C 放入。 构造方法初始化时需要 A 实例(C 尚未放入到 singletonFactories 中),于是调用了 getBean(A) 方法、
  4. Spring 容器创建单例“A” Bean,首先检测 singletonFactories 是否包含 A,发现没有于是正常创建 ,然后检测A是否包含在 singletonsCurrentlyInCreation 中 , 有 , 抛 出 BeanCurrentlyInCreationException 异常。
Copyright & copy lviter@163.com            updated 2024-02-06 09:54:56

results matching ""

    No results matching ""