Spring自问自答系列3----循环依赖

个人直觉告诉我循环依赖一定会致使死锁。 可是Spring支持循环依赖,因此本文就来探讨Spring底层是如何实现循环依赖的。java

Spring中循环依赖代码的书写

本文Spring的依赖注入经过注解形式实现 A.java缓存

class A {
    @Autowired
    private B b;
}

B.javapost

class B {
    @Autowired
    private A a;
}

第一眼会感受这依赖不是无限循环下去了吗? 可是想一想的确是可行的。this

Spring循环依赖的实现

首先须要了解SpringBeanFactory中的一些容器:code

缓存 用途
singletonObjects 用于存放彻底初始化好的 bean,从该缓存中取出的 bean 能够直接使用
earlySingletonObjects 存放原始的 bean 对象(还没有填充属性),用于解决循环依赖
singletonFactories 存放 bean 工厂对象,用于解决循环依赖
singletonsCurrentlyInCreation 存放当前正在建立的bean

循环依赖流程以下:对象

  1. getBean("a")
  2. 调用第二个getSingleton方法
  3. 发如今singletonFactory里没有A实例,开始实例化A
  4. 执行InstantiationAwareBeanPostProcessor.postProcessPropertyValues注入参数,发现须要B
  5. getBean("b")
  6. 实例化B
  7. 执行InstantiationAwareBeanPostProcessor.postProcessPropertyValues注入参数,发现须要A
  8. getBean("a")
  9. 调用第一个getSingleton方法获取A实例,注入进B实例中的A参数
  10. B实例初始化成功
  11. A实例注入B参数
  12. A实例初始化成功

关键代码

DefaultSingletonBeanRegistry.java中getSingleton(String beanName, boolean allowEarlyReference)方法:rem

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		
		// 判断bean是否正在建立过程当中 
		// 好比A正在初始化过程当中须要依赖注入B参数
		// Spring就须要区建立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();
					    
					    // earlySingletonObject用来解决循环依赖
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}
相关文章
相关标签/搜索