Spring中单例Bean实例创建的三个步骤:
-
创建对象,createBeanInstance
-
填充属性,populateBean
-
初始化操作(调用初始化方法),initializeBean
构造器循环依赖
无法解决,因为实例都还没有创建出来。比如A构造器依赖B,B构造器依赖A,在创建A实例需要B实例,创建B实例又需要A实例,所以构造器循环依赖无法解决。
setter方法循环依赖
setter方法循环依赖发生在第二步,解决的方法是,在实例化之后、填充属性之前将Bean实例放入缓存
缓存
// 一级缓存,存储创建完全成功的单例Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存,在Bean实例化、依赖注入、初始化后,会把Bean实例从三级缓存转移到二级缓存
// 如果需要生成代理对象,这里已经是代理对象了
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 三级缓存,主要来解决循环依赖问题,把刚实例化的对象封装成ObjectFactory,然后放入三级缓存
// 为什么封装成ObjectFactory
// 因为用直接的实例对象的引用的话,如果该实例对象后面会生成代理对象,就没办法做替换
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
三级缓存
AbstractAutowireCapableBeanFactory#doCreateBean
方法中会调用DefaultSingletonBeanRegistry#addSingletonFactory
把刚实例化的Bean对象封装成ObjectFactory对象放到三级缓存
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 省略...
// ObjectFactory实例
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 省略...
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
/**
* 如果单例池当中不存在才会add
* 因为如果bean存在单例池的话其实已经是一个完整的bean了
* 所以如果这个对象已经是一个完整的bean,就不需要关心,不需要进入if
* 如果一级缓存中没有改实例,则放入三级缓存中
*/
if (!this.singletonObjects.containsKey(beanName)) {
// 放入三级缓存
this.singletonFactories.put(beanName, singletonFactory);
/**
* 从二级缓存中remove掉当前的bean
* 这三个map当中其实其实存的都是一个对象,不能同时存在三个map
*/
// 从二级缓存中移除
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
用Lambda表达式封装成一个ObjectFactory对象,调用ObjectFactory#getObject
时会调用getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
// aop的AspectJAwareAdvisorAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor接口
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
调用AspectJAwareAdvisorAutoProxyCreator
的父类AbstractAutoProxyCreator#getEarlyBeanReference
方法
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// 使用动态代理,产生代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
二级缓存
在以下两个场景,会把Bean实例从三级缓存转移到二级缓存:
- 在Bean实例化、依赖注入、初始化后,
AbstractAutowireCapableBeanFactory#doCreateBean
方法中,调用DefaultSingletonBeanRegistry#getSingleton
- 获取Bean实例,会先去缓存中获取,
AbstractBeanFactory#doGetBean
方法中,调用DefaultSingletonBeanRegistry#getSingleton
DefaultSingletonBeanRegistry#getSingleton
,把Bean实例从三级缓存转移到二级缓存。如果需要生成代理对象,二级缓存这里已经是代理对象,有两点:
-
代理对象是在初始化后的
AbstractAutoProxyCreator#postProcessAfterInitialization
方法生成。 -
如果对象提前暴露给其他Bean,
singletonFactory.getObject()
会产生代理对象
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从一级缓存中获取单例对象
Object singletonObject = this.singletonObjects.get(beanName);
// isSingletonCurrentlyInCreation:判断当前单例bean是否正在创建中,也就是没有初始化完成
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从二级缓存中获取单例bean
singletonObject = this.earlySingletonObjects.get(beanName);
// allowEarlyReference:是否允许从singletonFactories中通过getObject拿到对象
if (singletonObject == null && allowEarlyReference) {
// 从三级缓存中获取单例bean
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 通过单例工厂获取单例bean
// 如果需要创建代理对象,这里会生成代理对象,调用AbstractAutoProxyCreator#getEarlyBeanReference方法
singletonObject = singletonFactory.getObject();
// 从三级缓存移动到了二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
一级缓存
在对Bean实例化、依赖注入、初始化之后,会将Bean实例保存到一级缓存。
DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory<?>)
方法中调用DefaultSingletonBeanRegistry#addSingleton
将Bean实例保存到一级缓存,删除在二级和三级对应的。一级缓存是真正对外暴露的Bean实例对象缓存。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 一级缓存
this.singletonObjects.put(beanName, singletonObject);
// 三级缓存
this.singletonFactories.remove(beanName);
// 二级缓存
this.earlySingletonObjects.remove(beanName);
// 已经注册的bean的名称集合
this.registeredSingletons.add(beanName);
}
}
在依赖注入时,会调用getBean
->doGetBean
->getSingleton
,会先从一级缓存取,一级没有去二级取,二级没有去三级取
为什么需要三级缓存
把实例化的bean通过封装成 ObjectFactory 放入第三级缓存做提前暴露,在DefaultSingletonBeanRegistry#getSingleton
方法中调用ObjectFactory#getObject
,当时放入三级缓存的是匿名内部类
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
调用了AbstractAutowireCapableBeanFactory#getEarlyBeanReference
方法,如果这里有用到aop,则会创建代理对象。所以二级缓存保存的是半成品的实例bean或者是代理对象(未进行依赖注入和初始化)。
这么看貌似两层缓存就可以解决循环依赖,为什么设计成三层缓存?
每次从第三级缓存获取(调用ObjectFactory#getObject
)都会创建一个代理对象,但需要的是单例对象,这是不行的(比如一个类中有两个相同类型的属性,就会两次获取)。所以借助二级缓存,只需要从二级缓存中拿取,没必要再执行一遍ObjectFactory#getObject
方法再产生一个新的代理对象,保证始终只有一个代理对象。