1.什么是循环依赖
就是我们的A类依赖(比如@Autowired B b)B类,这个时候我们去对A类的属性注入时,我们发现B可能没有,怎么办,去实例化,getBean();
但是我在getBean()B的时候,我们又发现A也还没实例化完!!
这个时候就A依赖B,B依赖A,就循环依赖了!!
2.三级缓存
//对于单例模式的Bean整个IOC容器中只创建一次,不需要重复创建
Object sharedInstance = getSingleton(beanName);
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
//判断当前单例Bean是否正在创建中,也就是没有初始化完成
//比如A的构造器依赖了B对象所以得先去创建B对象, 或则在A的populateBean过程中依赖了B对象,得先去创建B对象,这时的A就是处于创建中的状态。
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//从二级缓存获取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//从三级缓存获取
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
所以一级缓存为singletonObjects,就是我们的单例对象工厂的cache
//单例对象工厂的cache
private final Map singletonObjects = new ConcurrentHashMap<>(256);;
如果说,我们在一级缓存singletonFactories找不到的时候,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取
这个就是我们的二级缓存 earlySingletonObjects,提前暴光的单例对象的Cache,也是正在创建中的cache
private final Map earlySingletonObjects = new HashMap<>(16);
如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取
private final Map> singletonFactories = new HashMap<>(16);
如果获取到了我们再从三级缓存移除,放到二级缓存!也就是三级缓存移到二级缓存
3.三级缓存赋值
3.1 一级缓存
doGetBean方法中,Bean实例化完成后会调用getSingleton方法
sharedInstance = getSingleton(beanName, () -> {
try {
//创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义
//----------------------------往下走创建Bean-----------------------------------
return createBean(beanName, mbd, args);
}
getSingleton方法中在DefaultSingletonBeanRegistry.java调用addSingleton()方法
//方法会加入一级缓存,同时清空2.3级缓存
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
所以,一级缓存是存的我们完整的Bean对象,就是除了销毁整个生命流程结束了的Bean
3.2 三级缓存
那么我们3级缓存是个什么东西呢?我们可以看下,它是在哪里put值的,我们发现,singletonFactories是在
protected void addSingletonFactory(String beanName, ObjectFactory> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
赋值,而该方法就是在doCreateBean()中调用,但是调用时间是在实例化之后,在populateBean之前!!所以,三级缓存为我们实例化了,但是没有进行DI的一个半成品的Bean的集合!!
所以为什么Spring没有解决构造方法的循环依赖问题? 因为构造方法在实例化的时候调用,所以不会存到三级缓存!
1.A实例化后放入三级缓存singletonFactories中,进行populateBean,发现我A依赖B,并且B是没有实例化完成的
2.去实例化B,发现B又依赖于A,这个时候,我去一级缓存获取A,发现A也还没有bean完成,那么我会继续去三级缓存获取,发现了A
3.那么拿到A以后,B就能顺利的实例化完成,就算A不是完全的,但是B里面有A的对象引用。
4.B实例化完成后,继续A完成实例化。
5.整个A跟B全部实例化成功
4.为什么要用三级缓存
从刚才那个例子来看,我们二级缓存完全没有任何问题,那么spring为什么还要加一个三层!!
我们忽略了一个点,就是我bean实例化后的对象后面可能会改变,也就是我们的aop,会变成我们的代理类!!
大家看过源码应该都知道,我们的aop是哪里实现的?
是在我们初始化的方法,不是实例化的方法,也不是DI的方法,而是在
initializeBean(beanName, exposedObject, mbd); //里面的after方法,既然是代理增强,肯定得类初始化完成,不然没有任何意义
....
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
...
AbstractAutoProxyCreator.java.java的wrapIfNecessary()
所以,如果是AOP,如果只是用二级缓存的话,我们会得到一个什么问题?
singletonFactories 中是我们的原型对象,而singletonObjects中是我们的代理对象!!
因为singletonFactories是在我们代理之前加入的,而singletonObjects是在我对象初始化完后才进入的!!!
这样我缓存依赖的时候,B我拿到的是原型对象,但是其实我应该依赖的是代理对象!!所以,如果只有二级缓存依赖的话,会导致2个缓存的对象不一致
5.三级缓存为什么能解决?
private final Map> singletonFactories = new HashMap<>(16);
我们发现三级缓存,跟1.2级的缓存不一样,存的不是Object,而是一个匿名内部类,调用getEarlyBeanReference方法
最终调用到AbstractAutoProxyCreator.java的wrapIfNecessary,就是我们动态代理的方法