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方法。
-
getBean
-
doGetBean
-
getSingleton(beanName)---->getSingleton(beanName, true);
-
接下来会调用 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
-
接下来会调用 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)
-
调用 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
-
调用populateBean(beanName, mbd, instanceWrapper); 填充属性
会调用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”). -
调用org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
调用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”)
此时getBean会调用到 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)这个方法,我们再来debug一下这里。
-
最后会调用field.set(bean, value);这个方法给属性赋值
这里的第一次赋值是IndexService中的IndexDao属性赋值。属性赋值之前
第一次属性赋值之后
这样我们的IndexService中就已经引用上了IndexDao,只不过此时的IndexDao中的IndexService属性为null。
同样的道理,当我们第二次调用这个方法给属性赋值时,就可以发现此时我们的IndexDao也已经引用好了我们的IndexService。
第二次属性赋值之前
第二次属性赋值之后
当调用完这行代码后 我们的循环依赖就完成了。
三、总结
IndexDao—getBean—doGetBean–getSingleton(String beanName, boolean allowEarlyReference)(第一次)–getSingleton(String beanName, ObjectFactory<?> singletonFactory)–creatBean–doCreateBean–populateBean(填充属性)–initializeBean(初始化bean)
IndexService也是一样的流程。
简单来说就是利用了singletonFactories 这样一个Map的数据结构来缓存了一下我们还没有完成springBean的生命周期的对象。