循环依赖,其实就是循环引用,就是两个或者两个以上的 bean 互相引用对方,最终形成一个闭环,如 A 依赖 B,B 依赖 C,C 依赖 A。
Spring 循环依赖的场景有两种:
构造器的循环依赖。
field 属性的循环依赖。
对于构造器的循环依赖,Spring 是无法解决的,只能抛出 BeanCurrentlyInCreationException 异常表示循环依赖。Spring 只解决 scope 为 singleton 的循环依赖。对于scope 为 prototype 的 bean ,Spring 无法解决,直接抛出 BeanCurrentlyInCreationException 异常。
getSingleton
spring加载 bean 最初始的方法 AbstractBeanFactory 的 doGetBean(final String name, final Class
1 | protected Object getSingleton(String beanName, boolean allowEarlyReference) { |
这个方法主要是从三个缓存中获取,分别是:singletonObjects、earlySingletonObjects、singletonFactories 。
1 | //用于存放完全初始化好的 bean从该缓存中取出的 bean可以直接使用 |
singletonObjects :单例对象的 Cache 。
singletonFactories : 单例对象工厂的 Cache 。
earlySingletonObjects :提前曝光的单例对象的 Cache 。
第一级为 singletonObjects
第二级为 earlySingletonObjects
第三级为 singletonFactories
流程:
首先,从一级缓存 singletonObjects 获取,没有且当前指定的 beanName 正在创建,就再从二级缓存 earlySingletonObjects 中获取。
如果,还是没有获取到且允许 singletonFactories 通过 #getObject() 获取,则从三级缓存 singletonFactories 获取。如果获取到,则通过其 #getObject() 方法,获取对象,并将其加入到二级缓存 earlySingletonObjects 中,并从三级缓存 singletonFactories 删除。就从三级缓存升级到二级缓存了。
所以,二级缓存存在的意义,就是缓存三级缓存中的 ObjectFactory 的 #getObject() 方法的执行结果,提早曝光的单例 Bean 对象。
缓存中的数据
缓存中的数据从哪里添加进来,在 AbstractAutowireCapableBeanFactory 的 #doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) 方法中。
1 | // 解决循环依赖问题 |
当三级缓存 singletonFactories 和 二级缓存 earlySingletonObjects 中的值都有,在类 DefaultSingletonBeanRegistry 中的addSingleton(String beanName, Object singletonObject) 方法。
1 | protected void addSingleton(String beanName, Object singletonObject) { |
添加至一级缓存,同时从二级、三级缓存中删除。
至此:Spring 在创建 bean 的时候并不是等它完全完成,而是在创建过程中将创建中的 bean 的 ObjectFactory 提前曝光(即加入到 singletonFactories 缓存中)。
这样,一旦下一个 bean 创建的时候需要依赖 bean ,则直接使用 ObjectFactory 的 #getObject() 方法来获取了。