1、两个类相互引用
2、三级缓存可以解决循环依赖
(字段注入、setter注入、构造器注入的对象无法解决循环依赖)
3、Spring的生命周期(创建大概流程)
BeanDefinition的读取阶段:我们在往Spring容器注入Bean的时候,一般会通过比如xml方式,@Bean注解的方式,@Component注解的方式,其实不论哪一种,容器启动的时候都会去解析这些配置,然后为每个Bean生成一个对应的BeanDefinition,这个BeanDefinition包含了这个Bean的创建的信息,Spring就是根据BeanDefinition去决定如何创建一个符合你要求的Bean
Bean的实例化阶段:这个阶段主要是将你配置的Bean根据Class的类型创建一个对象出来
Bean的属性赋值阶段:这个阶段主要是用来处理属性的赋值,比如@Autowired注解的生效就是在这个阶段的
Bean的初始化阶段:这个阶段主要是回调一些方法,比如你的类实现了InitializingBean接口,那么就会回调afterPropertiesSet方法,同时动态代理其实也是在这个阶段完成的。
4、哪三级缓存
第一级缓存:singletonObjects 存放已经完全创建好的bean
第二级缓存:earlySingletonObjects
第三级缓存:singletonFactories 存的是每个Bean对应的ObjectFactory对象,通过调用这个对象的getObject方法,就可以获取到早期暴露出去的Bean。
单例bean通过三级缓存解决循环依赖,多例bean无法解决!!!
5、获取bean
org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
bean实例化结束后,会先把bean放入第三级缓存
6、三级缓存解决流程
项目启动,先创建A, 构建一个ObjectFactory对象放到三级缓存,依赖注入时,处理@Autowired修饰的B,去找B对象,二级缓存和三级缓存都么有,所以会去创建B对象,A对象的注入过程就暂停了,先实例化B,然后一样,构建一个ObjectFactory对象放到三级缓存,然后依赖注入,处理@Autowired修饰的A,查找A,查一级缓存、二级缓存没有,三级缓存有,掉三级缓存的getObject方法,获取到早期A,放到二级缓存(如果有其他循环依赖,可直接从二级依赖获取早期对象),删除三级缓存,虽然是早期的A对象,但是与完整的A对象是同一个。此时B对象的依赖注入完成,再经过其他阶段的处理,B对象创建完成,放入一级缓存,清空二三级缓存,再继续A对B的依赖注入,以及后续流程。
7、构造器注入无法解决循环依赖
三级缓存为什么不能解决循环依赖?
因为,A对象实例化结束后,才会放入三级缓存,发生循环依赖时,可通过三级缓存ObjectFactory.getObject()获取到早期A对象;
但是构造器注入发生在实例化时,此时A对象还没有实例化完成,不会放入三级缓存,那么创建B对象时,就不会从三级缓存中获取到早期A对象,那么就要去创建A,但是A正在创建,就会报错!
8、多例对象无法解决循环依赖
9、aop的代理对象的创建流程
假设有代理对象A需要创建,首先创建原型对象A,在创建原型对象前,有就会通过SmartInstantiationAwareBeanPostProcessor的前置处理器创建代理对象来代替原型对象A。
但是由于这里TargetSource=null,所以没有创建出代理对象
后续在BeanPostProcessor的后置处理器,生成代理对象。
AbstractAutoProxyCreator:
创建完成后,放入一级缓存,供后续getBean使用
10、代理对象A和无代理B的循环依赖
先创建代理对象A,实例化原型A后放入三级缓存,再依赖注入B,去实例化B,放入第三级缓存,再依赖注入A,去获取A,A存在第三级缓存中,所以调用三级缓存的singletonFactory.getObeject()方法获取到代理A,并放入二级缓存中。
获取代理对象
到这里,代理A的属性B的依赖注入完成了,继续代理A的创建。
因为上面原型A创建完成了,继续后面流程,
在处理BeanPostProcessor(AbstractAutoProxyCreator)的后置处理器时,由于之前处理循环依赖时,已经创建了代理A了,所以这里不需要再重复创建。
在初始化结束后,会获取缓存,发现二级缓存里有代理A,所以这里将代理A替换原型A
11、为什么使用三级缓存而不是二级缓存
三级缓存ObjectFactory的getBean()方法获取到的bean可能是两种类型,一是实例化阶段创建出的对象,二是代理对象。
如果舍弃二级缓存,那么如果是代理对象,每次都会重新生成一个新的代理对象;
如果舍弃三级缓存,提前暴露代理对象,依赖注入的可能跟最后创建好的不一样;