Spring - DI循环依赖

Spring中循环依赖的3种情况

  1. 构造器循环依赖
    构造器的循环依赖是不可以解决的,spring容器将每一个正在创建的bean标识符放在一个当前创建bean池中,在创建的过程一直在里面,如果在创建的过程中发现已经存在这个池里面了,这时就会抛出异常表示循环依赖了。

  2. setter循环依赖
    对于setter的循环依赖是通过spring容器提前暴露刚完成构造,但并未完成其他步骤(如setter注入)的bean来完成的,而且只能决定单例作用域的bean循环依赖,通过提前暴露一个单例工厂方法,从而使其他的bean能引用到该bean.当你依赖到了该Bean而单例缓存里面有没有该Bean的时候就会调用该工厂方法生产Bean。
    为什么不把Bean暴露出去,而是暴露个Factory呢?因为有些Bean是需要被代理的

  3. prototype范围的依赖
    对于“prototype”作用域bean,Spring容器无法完成依赖注入,因为“prototype”作用域的bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。

Spring是如何解决循环依赖的问题的?

以两个类A和B为例,通过set方式的循环依赖,看看Spring是如何解决的。

@Component
public class A {
  private B b;
  public void setB(B b) {
    this.b = b;
  }
}
@Component
public class B {
  private A a;
  public void setA(A a) {
    this.a = a;
  }
}

Spring实例化bean是通过ApplicationContext.getBean()方法来进行的。

  1. Spring尝试通过ApplicationContext.getBean()方法获取A对象的实例。由于Spring容器中还没有A对象实例,因而其会创建一个A对象,并将A并且保存单例缓存中,或者singletonFactories中。
  2. 因为A依赖了B对象,所以尝试递归的通过ApplicationContext.getBean()方法获取B对象的实例
  3. 但是Spring容器中此时也没有B对象的实例,所以会先创建一个B对象的实例。发现依赖A对象时,从单例缓存中查找,如果没有找到会从singletonFactories中查找,从而完成属性注入。
  4. 此时A对象和B对象都已经创建了,并且保存在Spring容器中了,只不过A对象的属性b和B对象的属性a都还没有设置进去。A将B注入成功,并注入A的其他属性值,自此即完成了循环依赖的注入。

源码

  1. doGetBean()是一个关键的方法(中间有省略),是ApplicationContext.getBean()的核心
protected  T doGetBean(final String name, @Nullable final Class requiredType,
    @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
  
  // 尝试通过bean名称获取目标bean对象,比如这里的A对象
  Object sharedInstance = getSingleton(beanName);
  // 我们这里的目标对象都是单例的
  if (mbd.isSingleton()) {
    // 这里就尝试创建目标对象,第二个参数传的就是一个ObjectFactory类型的对象。
    // 这里是使用Java8的lamada 表达式书写的,
    // 只要上面的getSingleton()方法返回值为空,则会调用这里的getSingleton()方法来创建 目标对象
    sharedInstance = getSingleton(beanName, () -> {
      try {
        // 尝试创建目标对象
        return createBean(beanName, mbd, args);
      } catch (BeansException ex) {
        throw ex;
      }
    });
  }
  return (T) bean;
}

第一个getSingleton()方法的作用是尝试从单例池中获取Bean,如果没有获取到,则判断是否正在创建中,且有工厂方法。有工厂方法,使用工厂方法创建Bean实例。

第二个getSingleton()方法的作用是尝试创建目标对象,并且为该对象注入其所依赖的属性。

  1. 第一个getSingleton()方法:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  
  // 尝试从单例池中获取目标对象,如果存在,则直接返回
  Object singletonObject = this.singletonObjects.get(beanName);
  
  // 如果单例池不存在目标对象,则判断当前对象是否已经处于创建中。
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    
    synchronized (this.singletonObjects) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
        
        // singletonFactories是一个Map,其key是bean的名称,值是一个ObjectFactory对象。
        // 取得Bean的工厂方法,如果存在通过工厂方法类创建Bean(singletonFactory.getObject())
        ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
        if (singletonFactory != null) {
          
          // 创建目标对象的实例
          singletonObject = singletonFactory.getObject();
          this.earlySingletonObjects.put(beanName, singletonObject);
          this.singletonFactories.remove(beanName);
        }
      }
    }
  }
  return singletonObject;
}
  1. 第二个getSingleton()方法:

	//创建单例模式Bean的实例对象
	if (mbd.isSingleton()) {
		//这里使用了一个工厂方法类(匿名内部类),定义了ObjectFactory的getObject的实现。
		sharedInstance = getSingleton(beanName, () -> {
			try {
				//创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				//显式地从容器单例模式Bean缓存中清除实例对象
				destroySingleton(beanName);
				throw ex;
			}
		});
		//获取Bean的实例对象
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	}

生成ObjectFactory的实例,并实现getObject方法。方法中调用createBean()。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(beanName, "Bean name must not be null");
	synchronized (this.singletonObjects) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			if (this.singletonsCurrentlyInDestruction) {
				throw new BeanCreationNotAllowedException(beanName,
						"Singleton bean creation not allowed while singletons of this factory are in destruction " +
						"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
			}
			// 将Bean设置为创建中
			beforeSingletonCreation(beanName);
			boolean newSingleton = false;
			boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet<>();
			}
			try {
				// 工厂方法创建Bean实例。
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			}
			catch (IllegalStateException ex) {
				// Has the singleton object implicitly appeared in the meantime ->
				// if yes, proceed with it since the exception indicates that state.
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					throw ex;
				}
			}
			catch (BeanCreationException ex) {
				if (recordSuppressedExceptions) {
					for (Exception suppressedException : this.suppressedExceptions) {
						ex.addRelatedCause(suppressedException);
					}
				}
				throw ex;
			}
			finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}
				afterSingletonCreation(beanName);
			}
			// 将Bean加入到单例池
			if (newSingleton) {
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}
  1. createBean方法的最终调用了doCreateBean()方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
  throws BeanCreationException {
  // 实例化当前尝试获取的bean对象。
  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) {
    
    // 将工厂方法放入到Map中。
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  }
  try {
    // 在初始化实例之后,填充属性及依赖对象。会递归的调用getBean()方法尝试获取目标bean
    populateBean(beanName, mbd, instanceWrapper);
  } catch (Throwable ex) {
    // ...
  }
  return exposedObject;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值