谈谈spring中的循环依赖

spring是如何解决循环依赖的,下面我将通过查看Spring源码,谈谈我自己的看法。

(以下的分析基于spring5.0版本源码,可以自行编译spring源码。)

一、问题描述

@Component
public class IndexDao {
	@Autowired
	private IndexService indexService; //在indexDao中引用了indexService
}

@Component
public class IndexService {
	@Autowired
	private IndexDao indexDao; //在indexService中引用了indexDao
}

在IndexDao中定义IndexServic属性并加上了@Autowired的注解,在IndexService中定义了IndexDao的属性,并加上了@Autowired注解自动装配。这就是循环引用。

二、问题分析

1、对象与bean
对象:java的普通对象
spring bean:也是Java的对象,但是它是存在spring容器中,并且是结果了完整的spring bean的实例化和初始化过程的(也可以说是拥有了完整的spring bean的生命周期的)。
2、分析
1、先来看看IndexDao是怎么初始化的

public class Test {
		public static void main(String[] args) {
			AnnotationConfigApplicationContext acc = new AnnotationConfigApplicationContext(AppConfig.class);
		}
	}

AnnotationConfigApplicationContext 我们利用这个类来初始化我们的spring环境,然后通过debug一步步跟进。
当我们去创建IndexDao的时候,回去容器中先拿看有没有这个bean会调用getBean这个方法,所以在getBean的时候打一个条件断点来跟进。然后debug运行Test的main方法。

  1. getBean
    谈谈spring中的循环依赖_第1张图片

  2. doGetBean
    谈谈spring中的循环依赖_第2张图片

  3. getSingleton(beanName)---->getSingleton(beanName, true);
    谈谈spring中的循环依赖_第3张图片
    谈谈spring中的循环依赖_第4张图片

  4. 接下来会调用 getSingleton(String beanName, ObjectFactory singletonFactory)
    谈谈spring中的循环依赖_第5张图片
    谈谈spring中的循环依赖_第6张图片

  5. 接下来会调用 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

    ----->调用doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)

    ----->调用 createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    谈谈spring中的循环依赖_第7张图片谈谈spring中的循环依赖_第8张图片

  6. 调用 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    谈谈spring中的循环依赖_第9张图片

  7. 调用populateBean(beanName, mbd, instanceWrapper); 填充属性
    谈谈spring中的循环依赖_第10张图片
    会调用org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues这个方法来进行@Autowired的属性填充。在IndexDao需要填充的属性是IndexService。同样的它还是会调用getBean方法从容器中去拿IndexService,所以我们在org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)方法中打一个条件断点,name.equals(“indexService”).

  8. 调用org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
    谈谈spring中的循环依赖_第11张图片
    调用getBean之后的流程就和我们之前创建IndexDao的流程是一样的了,先从容器中去拿,没有的话就创建,然后填充属性。
    getBean----->doGetBean------->getSingleton----->createBean—>doCreateBean—>populateBean–>postProcessPropertyValues
    最后在IndexService被创建出来了以后,它会去进行属性填充,调用getBean(indexDao),所以我们再到org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)这里打一个条件断点name.equals(“indexDao”)
    谈谈spring中的循环依赖_第12张图片
    此时getBean会调用到 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)这个方法,我们再来debug一下这里。
    谈谈spring中的循环依赖_第13张图片

  9. 最后会调用field.set(bean, value);这个方法给属性赋值

这里的第一次赋值是IndexService中的IndexDao属性赋值。属性赋值之前
谈谈spring中的循环依赖_第14张图片
第一次属性赋值之后
谈谈spring中的循环依赖_第15张图片
这样我们的IndexService中就已经引用上了IndexDao,只不过此时的IndexDao中的IndexService属性为null。

同样的道理,当我们第二次调用这个方法给属性赋值时,就可以发现此时我们的IndexDao也已经引用好了我们的IndexService。
第二次属性赋值之前
谈谈spring中的循环依赖_第16张图片
第二次属性赋值之后
谈谈spring中的循环依赖_第17张图片
当调用完这行代码后 我们的循环依赖就完成了。

三、总结

IndexDao—getBean—doGetBean–getSingleton(String beanName, boolean allowEarlyReference)(第一次)–getSingleton(String beanName, ObjectFactory singletonFactory)–creatBean–doCreateBean–populateBean(填充属性)–initializeBean(初始化bean)
IndexService也是一样的流程。
简单来说就是利用了singletonFactories 这样一个Map的数据结构来缓存了一下我们还没有完成springBean的生命周期的对象。
谈谈spring中的循环依赖_第18张图片

你可能感兴趣的:(spring,循环依赖,循环引用,spring,spring源码解析)