问题
public class A{
@Autowire
private B b;
}
public class B{
@Autowire
private A a;
}
这种情况是不是spring需要先实例化A(或者先B),实例化A之后填充属性的时候发现还需要依赖B然后需要实例化B,实例化B之后发现还需要填充属性A,然后是不是又要去实例化A,这不就造成死循环了吗,spring是怎么解决这种互相依赖的?
图解:
总结
其实最主要的就是 singletonFactories 这个map,A会先实例化好对象,然后把对象放到这个map中去,然后再填充属性的时候需要依赖注入B,实例化B的之后,往B填充属性的时候,依赖注入A,这时候会从singletonFactories这个map中获取对象,但是这个对象还没有完成属性填充和初始化,B拿到A的对象之后,B进行属性填充和bean的初始化,然后依赖注入给了A对象,完成循环依赖。
面试
- 1.三级缓存
- 2.bean工厂提前暴露
三级缓存
spring 三级缓存是指什么
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//先从一级缓存尝试获取 :singletonObjects
Object singletonObject = this.singletonObjects.get(beanName);
//一级缓存获取不到,判断 bean是否在创建中:isSingletonCurrentlyInCreation
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从三级缓存获取数据:earlySingletonObjects
singletonObject = this.earlySingletonObjects.get(beanName);
//如果三级缓存获取不到,allowEarlyReference:表示是否可以循环依赖,可以设置false
//表示不能循环依赖
if (singletonObject == null && ,allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//三级缓存获取失败,从bean工厂获取bean(提前暴露bean工厂)
singletonObject = singletonFactory.getObject();
//把从二级缓存获取到的数据放到三级缓存,之后如果还有循环依赖,就可以从
//三级缓存获取,这样就不用从bean工厂获取bean,因为bean工厂重新获取bean
//是比较慢
this.earlySingletonObjects.put(beanName, singletonObject);
//删除二级缓存的数据
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
总结
- 1.一级缓存是:singletonObjects,也就是单例池
- 2.二级缓存是:singletonFactories:也就是提前暴露bean工厂,存放着获取bean的方法
- 3.三级缓存是:earlySingletonObjects:一级获取不到,从三级获取,三级获取不到,从二级的bean工厂获取,从二级的bean工厂获取到之后删除,二级的bean工厂,把bean放到三级缓存。
bean工厂提前暴露
在上面的三级缓存中,可以从二级缓存获取到bean,这个bean是怎么获取到的。
//在实例化bean之后,将bean工厂提前暴露在 singletonFactories 二级缓存中
//() -> getEarlyBeanReference(beanName, mbd, bean) 这是lamb表达式
//等到循环依赖的时候调用 getObject 会调用 getEarlyBeanReference 方法
//这就是bea 工厂的提前暴露
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
getEarlyBeanReference
故名思意,就是获取早期的bean引用其实就是调用bean后置处理器的 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) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
getEarlyBeanReference 其实是aop才用到的,只有开启了aop,然后需要进行切面织入的时候。
AbstractAutoProxyCreator#getEarlyBeanReference
这就设计到spring的aop知识了
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
//动态代理
return wrapIfNecessary(bean, beanName, cacheKey);
}