您的位置:首页 > 编程语言 > Java开发

【八】Spring IoC 最全源码详解之bean的循环依赖

2019-03-01 19:51 274 查看
版权声明:本博客原创文章遵循CC BY-NC-SA 2.5 CN 协议 https://blog.csdn.net/wuyuwei/article/details/88058455

先有鸡还是先有蛋,这是一个问题。

目录

1. 什么是循环依赖

2. Spring针对循环依赖的解决方案

2.1 亚当的登场

2.2 夏娃的诞生

2.3 寻找亚当

2.4 完成亚当的创建

3. 附录:本项目工程文件

1. 什么是循环依赖

你中有我,我中有你,就是循环依赖。举个例子,本文使用的项目中“yadang”与“xiawa”这两个bean就是循环依赖的(参考附录)。Class Adam中的Eve eve属性依赖Spring框架自动注入,同样Class Eve中的Adam adam属性也依赖于框架的自动注入。并且,Adam和Eve都是单例的。这种情况下,就构成了两个对象的循环依赖。

2. Spring针对循环依赖的解决方案

二话不说,先来一张图描述Spring对于循环依赖的解决方案。

如果您是按照本系列文章的序号依次读完再到这里的,那么根据上面这张图你就已经能看透Spring框架处理循环依赖的方式了,强烈建议您不要看下文,自己根据上图和写个demo debug分析分析印象更深

如果您仅仅想知道Spring是如何做到的,那我们就开始吧。

2.1 亚当的登场

假设目前“亚当”和“夏娃”这两个bean都还未曾创建,现在流程走到亚当的创建流程(蓝色流程)。因为亚当创建之前不曾有亚当创建出来被容器托管,故流程会很顺利的走到createBean。在createBean之前,会通过beforeSingletonCreation在bean工厂的singletonsCurrentlyInCreation Set集合中添加亚当这个bean的beanName——“yadang”。

随后流程陷入doCreateBean方法中,首先通过createBeanInstance创建出亚当这个对象adamObj,请注意目前亚当它目前长这样:

[code]adam:
eve  : null

接着流程通过addSingletonFactory,如果在singletonObjects中没有找到“yadang”这个对象,那么就尝试在bean工厂的singletonFactories中进行如下步骤:

[code]1.添加<yadang, singletonFactory>到中singletonFactories中,元素的key是亚当的beanName,value是创造该对象所用的bean工厂。

2.在registeredSingletons中添加“yadang”。

3.在earlySingletonObjects中移除key为“yadang”的对象(不存在也不会报错)。

到目前为止,bean工厂中各个缓存容器的值如下:

singletonObjects null

registeredSingletons

"yadang"

singletonFactories

<yadang, factory>

earlySingletonObjects

null

singletonsCurrentlyInCreation

"yadang"

亚当创建完成后,就需要通过populateBean对属性进行依赖注入,流程会陷入inject方法,最终通过doResolveDependency一路调用到getBean(“xiawa”)。这时流程就走到了夏娃的创建流程(粉色流程)。

2.2 夏娃的诞生

由于bean工厂中singletonObjects并未缓存有夏娃这个bean(beanName是“xiawa”)。那么夏娃的创建流程就和亚当的类似,它也会通过doCreateBean方法中createBeanInstance创建出夏娃eveObj这个对象

[code]eve:
adam  : null

 然后也通过addSingletonFactory,如果在singletonObjects中没有找到“xiawa”这个bean,那么就尝试在bean工厂的singletonFactories中进行如下步骤:

[code]1.添加<xiawa, singletonFactory>到singletonFactories中。

2.在registeredSingletons中添加“xiawa”。

3.在earlySingletonObjects中移除key为“xiawa”的对象(不存在也不会报错)。

 到目前为止,bean工厂中各个缓存容器的值如下:

singletonObjects null

registeredSingletons

"yadang", "xiawa"

singletonFactories

<yadang, factory>, <xiawa, factory>

earlySingletonObjects

null

singletonsCurrentlyInCreation

"yadang", "xiawa"

同样的,夏娃创建完成后,就需要通过populateBean对属性进行依赖注入,流程会陷入inject方法,最终通过doResolveDependency一路调用到getBean(“yadang”)。这时流程又就走到了亚当的创建流程(蓝色流程)。

2.3 寻找亚当

再次进入蓝色的getBean-->doGetBean-->getSingleton("yadang")-->getSingleton("yadang",true)。

[code]protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 当前singletonObjects中不存在yadang和xiawa对象,故singletonObject=null
Object singletonObject = this.singletonObjects.get(beanName);
// "yadang", "xiawa", 显然存在"yadang"
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// earlySingletonObjects中不存在"yadang", "xiawa",传入的allowEarlyReference为true
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 通过工厂获取到singletonFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
1c6f4

this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}

根据bean工厂中各个缓存容器的值层层过滤后,最终满足所有条件。进入到最内层if语句块,执行方法singletonObject = singletonFactory.getObject();该方法是DefaultSingletonBeanRegistry中addSingletonFactory方法的回调函数() -> getEarlyBeanReference(beanName, mbd, bean)。它最终会执行AbstractAutowireCapableBeanFactory的getEarlyBeanReference方法后得到缓存的bean。有可能你会好奇入参是怎么来的,根据“yadang”拿到的singletonFactory 中有四个缓存值如下:1是DefaultListableBeanFactory,2,3,4就是入参。因为DefaultListableBeanFactory继承了AbstractAutowireCapableBeanFactory,故父类的getEarlyBeanReference方法可以调用。

[code]singletonFactory = {AbstractAutowireCapableBeanFactory$lambda@1915}
arg$1 = {DefaultListableBeanFactory@1387} "org.springframework.beans.factory.support.DefaultListableBeanFactory@36bc55de: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,caseApplication,yadang,xiawa,human,appleFactory,gardenofEden]; root of factory hierarchy"
arg$2 = "yadang"
arg$3 = {RootBeanDefinition@1865} "Root bean: class [com.Hodey.learn.bean.Adam]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [F:\gitSource\HodeyLab\case\target\classes\com\Hodey\learn\bean\Adam.class]"
arg$4 = {Adam@1867}

最终经过上述步骤返回出入参4对象,如果使用了动态代理,那么返回代理对象。在此之前还要对earlySingletonObjects和singletonFactories做相应的操作。此时bean工厂中各个缓存容器的值如下:

singletonObjects null

registeredSingletons

"yadang", "xiawa"

singletonFactories

 <xiawa, factory>

earlySingletonObjects

<"yadang", adam>

singletonsCurrentlyInCreation

"yadang", "xiawa"

拿到bean后还需要进入getObjectForBeanInstance分支处理万一拿到的bean是FactoryBean的情况:

[code]protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 首先进行是否是FactoryBean推断,如果beanInstance是null,则返回null;如果
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 如果beanInstance和name关于是否FactoryBean自相矛盾的异常抛出
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
}
// 普通bean直接返回beanInstance
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 如果是FactoryBean,先看看有没有想要得到的目标对象在之前有没有造出来。如果没有就通过FactoryBean造一个。
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 让FactoryBean造一个beanName的对象
// 内部调用doGetObjectFromFactoryBean(factory, beanName)#factory.getObject()方法的干活。factory是FactoryBean的实现类。
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}

最终通过几步简单的调用步骤后,返回最终获取到的adam对象,红色doResolveDependency方法的getBean方法执行完成执行后一路返回,最终在inject中完成夏娃对象adam属性的装配,这是eveObj对象:

[code]eve:
adam  : adamObj

 完成eve对象的装配后一路返回doGetBean方法。随后通过afterSingletonCreation方法移除singletonsCurrentlyInCreation中的中的“xiawa”,通过getSingleton(String beanName, ObjectFactory<?> singletonFactory)向容器中的做如下操作:

[code]1. singletonObjects中添加<"xiawa", eveObj>
2. singletonFactories中移除<"xiawa", factoryObj>
3. earlySingletonObjects中移除<"xiawa", eveObj>
4. registeredSingletons中添加"xiawa"

这样bean工厂中各个缓存容器的值如下:

singletonObjects <"xiawa", eveObj>

registeredSingletons

"yadang", "xiawa"

singletonFactories

null

earlySingletonObjects

<"yadang", adam>

singletonsCurrentlyInCreation

"yadang"

这样,夏娃的创建过程就完毕了。流程一路返回eveObj对象到蓝色的doResolveDependency方法。

2.4 完成亚当的创建

一路返回eveObj对象到inject完成adamObj的装配:

[code]adam:
eve  : eveObj

随后一路返回到getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法的afterSingletonCreation和addSingleton方法操作bean工厂中各个缓存容器后的值如下:

singletonObjects <"xiawa", eveObj>, <"yadang", adamObj>

registeredSingletons

"yadang", "xiawa"

singletonFactories

null

earlySingletonObjects

null

singletonsCurrentlyInCreation

null

此时亚当和夏娃这两个bean都缓存在了singletonObjects中,完成了这两个循环依赖bean的创建过程。

循环依赖仅仅是Spring创建bean过程中的一个小小的插曲,时间还停留在原来的6:00。下篇文章我们将会深入分析本系列文章最后一个内容——initializeBean。敬请期待。

3. 附录:本项目工程文件

[code]@Component("yadang")
public class Adam {

@Autowired
private Eve eve;

public void sayHello(){
System.out.println("你好,我是" + this.getClass() + ". 我爱" + eve.getClass());
}
}
[code]@Component("xiawa")
public class Eve {

@Autowired
private Adam adam;

public void sayHello(){
System.out.println("你好,我是" + this.getClass() + ". 我爱" + adam.getClass());
}
}
[code]@Service
public class GardenofEden {

@Autowired
private Adam adam;

@Resource(name = "xiawa")
private Eve eve;

public void sayHello(){
adam.sayHello();
eve.sayHello();
}
}
[code]@ComponentScan("com.Hodey")
public class CaseApplication {

public static void main(String[] args) {

AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(CaseApplication.class);
GardenofEden garden = ctx.getBean(GardenofEden.class);
garden.sayHello();
}
}

执行结果:

[code]你好,我是class com.Hodey.learn.bean.Adam. 我爱class com.Hodey.learn.bean.Eve
你好,我是class com.Hodey.learn.bean.Eve. 我爱class com.Hodey.learn.bean.Adam

 

 

 

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: