什么是循环依赖

//A对象依赖B对象,B对象依赖A对象
class A{
	public B b;
}
class B{
	public A a;
}

Bean的创建周期

1.根据class生成BeanDefinition
2.new AService(); //原始对象
3.依赖注入填充属性
4.Aware
5.初始化
6.AOP
7.将对象放入单例池

在spring中当A创建到第3步时,去单例池中拿需要注入的bean对象,因为B还没创建找不到,则会去创建B对象的对象,此时B开始创建,B创建到第三步时,找不到A对象,这样就出现了循环依赖

使用缓存解决

所以当A创建到时,将A对对象放入缓存中,Map<aService,原始对象>

然后B对象创建,在属性注入时在单例池中找不到,就可以从缓存中得到aService的原始对象

此时便可初步解决bean的循环依赖

二级缓存出现的问题

不过若A对象代码中存在AOP,则会生成代理对象,会把代理对象存入单例池,这个时候B对象注入的A是原始对象,与单例池中A不是同一个对象

三级缓存

为了解决这个问题,需要在增加一个步骤,在A对象创建时需要增加一个缓存表示A对象正在创建中

1.1:放入creatingMap

此时B创建在单例池中找不到A属性,可以在creatingMap中判断A对象是不是正在在创建,然后提前让A对象进行aop,这个时候A对象4.5步还没执行,不能将aop生成的代理对象放入单例池,比如此时A对象还有C对象的属性,C对象也会创建A对象的aop代理对象,这个时候就会出现2个代理对象

此时需要二级缓存,map<aService,代理对象>,这个时候C对象在二级缓存就可以找到B创建时生成的代理对象

而生成代理对象时候需要原始对象,需要在加一级缓存存入原始对象,就是1.1步骤

流程:A对象创建发现依赖B对象,会从单例池中找,找不到在从二级缓存找,执行1.1步骤,B对象创建,B对象创建发现依赖A对象,会先从一级缓存中找,找不到在从二级缓存中找,则从三级缓存里找,就会找到1.1步骤存入的正在创建的对象(lambda(原始对象)),执行三级缓存中lambda表达式进行aop创建,将代理对象放入二级缓存,并且将三级缓存中原始对象删除

总结:二级缓存中有对象,则三级缓存无对象,二级与三级需要原子性操作,需要加锁,所以使用hashmap,而一级缓存使用currenthashmap