Spring 循环依赖

Spring —— 循环依赖

Spring Bean默认都是以单例的形式存在,但是也支持prototype形式,这里主要介绍单例Bean。

示例

@Component
public class X {

    @Autowired
    private Y y;

    public X() {
        System.out.println("X construct...");
    }
}
@Component
public class Y {

    @Autowired
    private X x;

    public Y() {
        System.out.println("Y construct...");
    }
}
@Configuration
@ComponentScan("com.ljc")
public class AppConfig {
}
public class Test {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        context.getBean(X.class);

        // 优雅关闭,SpringWEB中已有相关实现
        context.registerShutdownHook();
    }

Bean循环依赖过程

getSingleton方法时获取单例Bean的方法,其中包含了对象正在创建的标记、对象的创建和初始化、对象放入单例缓冲几个重要步骤。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {

	// 使用单例对象的高速缓存Map作为锁,保证线程同步
	synchronized (this.singletonObjects) {
		// 从单例对象的高速缓存Map中获取beanName对应的单例对象
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果单例对象获取不到
		if (singletonObject == null) {

			// 循环依赖提前标记
			beforeSingletonCreation(beanName);

			boolean newSingleton = false;

			try {
				// 从单例工厂中获取对象,如果还未创建,会创建一个实例
				singletonObject = singletonFactory.getObject();
				// 生成了新的单例对象的标记为true,表示生成了新的单例对象
				newSingleton = true;
			}

			if (newSingleton) {
				// 放生成的bean放入单例缓存中
				addSingleton(beanName, singletonObject);
			}
		}
		// 返回该单例对象
		return singletonObject;
	}
}

beforeSingletonCreation(beanName)会在实例化对象前将beanName放入到一个Set集合中,表明当前bean处于创建过程。

接着就是在执行singletonFactory.getObject();方法时,如果不存在对象就会创建一个对象。

下面是创建Bean的最主要方法,这里只罗列的部分较为重要的代码:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {

	BeanWrapper instanceWrapper = null;
	// 获取factoryBean实例缓存
	if (mbd.isSingleton()) {

		instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
	}
	if (instanceWrapper == null) {
		// 没有就创建实例, 这里通过newInstance创建对象
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}

	// 判断当前bean是否需要提前曝光:单例&允许循环依赖&当前bean正在创建中,检测循环依赖
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		if (logger.isTraceEnabled()) {
			logger.trace("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		// 为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	Object exposedObject = bean;
	try {
		// 属性渲染
		populateBean(beanName, mbd, instanceWrapper);

		// 执行初始化init方法
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	catch (Throwable ex) {

	}

}

当从factoryBeanInstanceCache缓存中取不到相关的Bean时,就会通过createBeanInstance方法创建一个Object对象(这里还不能说是一个Bean对象,因为只是通过反射实例化出了一个对象,并没有进行过属性渲染,执行初始化方法等步骤);

后面根据isSingleton() && allowCircularReferences &&isSingletonCurrentlyInCreation(beanName))三个boolean值来判断是否开启循环依赖,其中isSingleton()isSingletonCurrentlyInCreation(beanName))在单例对象中都是会返回true,所以一般可以通过修改allowCircularReferences的值来设置是否开启循环依赖,而默认是为true,即支持循环依赖。

当earlySingletonExposure为true时执行下面方法

​ addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(singletonFactory, "Singleton factory must not be null");
   synchronized (this.singletonObjects) {
      // 如果单例对象的高速缓存【beam名称-bean实例】没有beanName的对象
      if (!this.singletonObjects.containsKey(beanName)) {
         // 将beanName,singletonFactory放到单例工厂的缓存【bean名称 - ObjectFactory】
         this.singletonFactories.put(beanName, singletonFactory);
         // 从早期单例对象的高速缓存【bean名称-bean实例】 移除beanName的相关缓存对象
         this.earlySingletonObjects.remove(beanName);
         // 将beanName添加已注册的单例集中
         this.registeredSingletons.add(beanName);
      }
   }
}

该方法会将一个singletonFactory放入到singletonFactoriesMap中,然后从earlySingletonObjects删除。这里就是常说的对象的提前暴露

这个singletonFactory其实就是之前实例化生成的对象经过几层包装生成的ObjectFactory对象,这里之所以不直接将生成的bean对象放入到Map中,是因为该对象还不是最终的Bean,后续还要经历一些生命周期,例如AOP增强,最终生成一个代理对象。

添加到Map后就会调用populateBean方法,这里就是产生依赖注入环节的地方。

上一篇:spring5源码阅读2spring容器启动


下一篇:如何记忆 Spring Bean 的生命周期