跳转至

Spring 如何避免并发获取不完整的 Bean

一、问题

多线程同时创建 Bean,可能拿到半成品。

二、解决

1. synchronized

getBean 方法 synchronized:

public Object getBean(String name) {
    synchronized (singletonObjects) {
        // 检查是否已存在
    }
}

2. 三级缓存检查

Object getSingleton(String name) {
    Object singleton = singletonObjects.get(name);
    if (singleton != null) return singleton;

    // 检查早期 Bean
    singleton = earlySingletonObjects.get(name);
    if (singleton != null) return singleton;

    // 检查 ObjectFactory
    ObjectFactory<?> factory = singletonFactories.get(name);
    if (factory != null) {
        singleton = factory.getObject();
        earlySingletonObjects.put(name, singleton);
        singletonFactories.remove(name);
    }
    return singleton;
}

3. 双重检查

if (singletonObjects.containsKey(name)) return ...;
synchronized (lock) {
    if (singletonObjects.containsKey(name)) return ...;
    // 创建
}

三、为什么安全

  • 同一时刻只有一个线程创建 Bean。
  • 其他线程等待。
  • 拿到的要么是完整 Bean,要么是早期 Bean(但早期 Bean 是已经实例化的,只是属性没填充完)。

四、早期 Bean 安全吗

早期 Bean 是实例化完的,只是属性没填充。其他线程拿到: - 如果只是引用,没问题。 - 如果马上调用方法,可能 NPE。

Spring 保证:同一线程内,Bean 创建完才返回。其他线程拿到的是早期引用,但最终会指向完整 Bean。

五、总结

  • synchronized 保证同一时刻只有一个线程创建。
  • 三级缓存保证其他线程能拿到早期引用。
  • 早期引用最终会指向完整 Bean。

一句话

Spring 用 synchronized + 三级缓存,既解决循环依赖,又保证并发安全。