分类: Java
2021-09-23 19:39:43
循环依赖问题的解决方案:
DefaultSingetonBeanRegistry 的三级缓存
/** Cache of singleton objects: bean name to bean instance. */。一级缓存
private final Map
/** Cache of singleton factories: bean name to ObjectFactory. */ 三级缓存
private final Map
/** Cache of early singleton objects: bean name to bean instance. */。二级缓存
private final Map
三个级别的缓存存放顺序是3 2 1 查找顺序是 1 2 3
1.三级缓存解决循环依赖问题的关键是什么?为什么通过提前暴露对象能够解决问题。
实例化和初始化分开操作,在中间过程中给其他对象赋值的时候,并不是一个完整对象,而是把半成品(完成实例化,但是没有完成初始化)对象赋值给了其他对象。
2.如果只使用一级缓存能不能解决这个问题
不能。在整个处理过程中,缓存中存放的是半成品和成品对象,如果只有一级缓存,那么半成品和成品都会放到一级缓存中。有可能在获取过程中获取到半成品对象,此时半成品对象是无法使用的,不能直接进行相关处理,因此需要把半成品和成品的存放空间分割开来。
3.只使用二级缓存行不行?为什么需要三级缓存
如果能保证所有的bean对象都不去调用getEarlyBeanReference方法,因为三级缓存中存放的就是beanName->getEarlyBeanReference,就可以不用三级缓存。只是使用二级缓存就可以。
使用三级缓存的本质是解决AOP代理问题!!!
4.如果某个Bean对象代理对象,会不会创建普通的bean对象?
会,首先会创建普通对象,然后依据条件查看是否符合代理条件,如果符合的话,会使用代理对象将普通对象覆盖掉。
/**
* Obtain a reference for early access to the specified bean,
* typically for the purpose of resolving a circular reference.
* @param beanName the name of the bean (for error handling purposes)
* @param mbd the merged bean definition for the bean
* @param bean the raw bean instance
* @return the object to expose as bean reference
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
5.使用了三级缓存就可以解决这个问题?
当一个对象需要被代理的时候,在整个创建过程中是包含了两个对象。一个是普通对象,一个是代理生成的对象。bean默认都是单例。那么我们在整个生命周期的处理过程,一个beanname能对应两个bean对象吗?不能,既然不能的话,保证我在使用的时候,加一层判断,判断是否需要进行代理的处理。
6.我怎么知道你什么时候使用呢?
因为不知道什么时候进行调用,所以通过一个匿名内部类的方式,在使用的时候直接对普通对象进行覆盖操作。保证全局唯一。
1.一级缓存放置成品对象
2.二级缓存放置半成品对象
3.三级缓存放置lambda表达式,来完成代理对象的覆盖过程