Spring整个解决循环依赖问题的实现思路如下图代码。对于整体过程,需要理解两点:
- Spring是通过递归的方式获取目标bean及其所依赖的bean的;
- Spring实例化一个bean的时候,是分两步进行的,首先实例化目标bean,然后为其注入属性。
结合这两点,也就是说,Spring在实例化一个bean的时候,是首先递归的实例化其所依赖的所有bean,直到某个bean没有依赖其他bean,此时就会将该实例返回,然后反递归的将获取到的bean设置为各个上层bean的属性的。
代码:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // 实例化当前尝试获取的bean对象,比如A对象和B对象都是在这里实例化的 BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } // 判断Spring是否配置了支持提前暴露目标bean,也就是是否支持提前暴露半成品的bean boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // 如果支持,这里就会将当前生成的半成品的bean放到singletonFactories中,这个singletonFactories // 就是前面第一个getSingleton()方法中所使用到的singletonFactories属性,也就是说,这里就是 // 封装半成品的bean的地方。而这里的getEarlyBeanReference()本质上是直接将放入的第三个参数,也就是 // 目标bean直接返回 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } try { // 在初始化实例之后,这里就是判断当前bean是否依赖了其他的bean,如果依赖了, // 就会递归的调用getBean()方法尝试获取目标bean populateBean(beanName, mbd, instanceWrapper); } catch (Throwable ex) { // 省略... } return exposedObject; }