Spring循环依赖原理

Spring循环依赖的原理解析

1、什么是循环依赖?

​ 我们使用Spring的时候,在一个对象中注入另一个对象,但是另外的一个对象中也包含该对象。如图:

Spring循环依赖原理

在Student中包含了teacher的一个属性;

在Teacher中包含有student的属性。这样就形成了一个循环依赖。

2、代码描述

xml配置文件

Spring循环依赖原理

testCycle.java
private static void testCycle(){
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("cycle.xml");
		Teacher teacher = applicationContext.getBean(Teacher.class);
		System.out.println(teacher);
		Student student = applicationContext.getBean(Student.class);
		System.out.println(student);
	}

	public static void main(String[] args) {
		testCycle();
	}
Student.java
public class Student {
   private Teacher teacher;

   public Teacher getTeacher() {
      return teacher;
   }
   public void setTeacher(Teacher teacher) {
      this.teacher = teacher;
   }
}
Teacher.java
public class Teacher {

   private Student student;

   public Student getStudent() {
      return student;
   }
   public void setStudent(Student student) {
      this.student = student;
   }
}

3、 测试结果

Spring循环依赖原理

此处输出的teacher中包含有student对象,student对象中也包含有teacher对象,且包含的对象都是不为null的。

4、为什么能够循环依赖解释

先给出一张图

Spring循环依赖原理

在Spring创建bean的时候肯定也是一个一个去创建的。首先肯定会先去走一个(Teacher/Student)生命周期。这里以Teacher为例,当Spring去getBean(teacher)的时候,首先会去容器中获取,获取不到就会去创建teacher,当teacher创建完成后,会给teacher的属性(student)赋值,实际上容器中没有student对象,这时候也会去创建student对象,当student创建的时候会去给student中的teacher属性赋值,teacher之前已经创建过了,此时去getBean(teacher)是能够拿到的(注意:此时的teacher中student属性并没有赋值),这样student就创建完成了,那么就会回到teacher的student属性赋值的步骤,此时student已经创建是可以用getBean()拿到的,这样teacher对象就创建完毕了。然后回到第一步去创建student对象,这里student对象在创建teacher的时候就已经创建,可以直接使用getBean()获取到。给student中的属性赋值的时候也是一样,能够直接获取到teacher。自此循环依赖就已经结束了。

5、疑问

  1. 当我在给Teacher属性student的赋值的时候是怎么去getBean()的?
  2. 当给student中属性teacher赋值的时候getBean()为什么能够取到teacher?
  3. 为什么获取到的teacher属性是为完成注入的?

6、源码解释

整体的方法线

Spring循环依赖原理

先看看源码:

getBean()->doGetBean()

getBean() -> doGetBean() 实际上是 doGetBean 再去获取bean对象

public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
      throws BeansException {

   return doGetBean(name, requiredType, args, false);
}

/**
 * Return an instance, which may be shared or independent, of the specified bean.
 * 返回指定 bean 的一个实例,该实例可以是共享的,也可以是独立的。
 */
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {

   // 转换beanName,FactoryBean的情况下beanName为&beanName,这里就是去掉&符号
   String beanName = transformedBeanName(name);
   Object beanInstance;

   // Eagerly check singleton cache for manually registered singletons.
   // 急切检查单例缓存从手动创建的单例中,获取bean判断是否存在当前beanName的bean
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isTraceEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
      				... 省略代码...
      }
      beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      // 没有获取到,如果已经创建bean的实例,我们在一个循环引用中。当前的bean是否为正在创建中
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // Check if bean definition exists in this factory.
      // 检查该工厂中是否存在bean的定义
      BeanFactory parentBeanFactory = getParentBeanFactory();
     ... 省略代码...
      if (!typeCheckOnly) {
         // 标记bean已经创建,正在创建
         markBeanAsCreated(beanName);
      }

      StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
            .tag("beanName", name);
      try {
         if (requiredType != null) {
            beanCreation.tag("beanType", requiredType::toString);
         }
         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // Guarantee initialization of beans that the current bean depends on.
         // 保证当前的bean所依赖的bean已经初始化
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dep : dependsOn) {
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               registerDependentBean(dep, beanName);
               try {
                  getBean(dep);
               }
               catch (NoSuchBeanDefinitionException ex) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值