Spring 如何避免并发获取不完整的 Bean¶
一、问题¶
多线程同时创建 Bean,可能拿到半成品。
二、解决¶
1. synchronized¶
getBean 方法 synchronized:
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 + 三级缓存,既解决循环依赖,又保证并发安全。