spring5源码解读4springIOC实例化,注入解决循环依赖

编程

但是循环依赖 问题没有解读,本章重点解读

先声明:1 循环依赖只允许发生在单例的情况,多例直接报错;

               2 只允许无参构造函数的单例发生,有参构造函数的注入是不能保证循环依赖的

首先看示例代码:BeanA 持有 BeanB 的引用,BeanB 持有BeanA 的引用,这就导致了一个循环依赖的问题

解决循环依赖的原理:

                    1 当spring ICO 实例化BeanA 完成时,判断BeanA是否允许提前暴露,如果允许放入三级缓存

                    2 发现有属性BeanB需要注入,则会触发BeanB 的实例化,此时BeanA的没有完全实例化(因为没完成属性注入)

                    3 BeanB 的实例化,完成之后也会判断是否提前暴露,如果允许则放入缓存

                    4 这时BeanB的实例化完成了,但是有属性BeanA 需要注入

                    5 这里又触发了BeanA 的实例化,先从一级取不到,二级 取不到,在三级缓存中里面取到了

                    6 把从三级缓存取到部分完成的BeanA实例(因为此时BeanA还没完成注入),放入二级缓存,并删掉三级缓存的BeanA

                    7  把BeanA注入给BeanB实例,然后层层返回,BeanB完成实例化,把BeanB放入一级缓存,删掉BeanB在二,三级缓存

                    8  把BeanB注入给BeanA ,这时BeanA完成实例化 ,把BeanA放入一级缓存,删掉BeanB在二,三级缓存 。

总结:循环依赖的关键就是这三层缓存的利用,三级缓存取比较复杂,所以才用二级缓存,大部分对象是从一级缓存中取的。

简单复述:

实例化A -->A放入缓存-->注入B触发B实例化-->B放入缓存-->注入A出发A实例化-->缓存中取A-->把A注入B-->完成B实例化--->B注入A-->A完成实例化

下面用源码跟踪的方式理清这个循环依赖:

第 1 步  进入AbstractBeanFactory.java 的 doGetBean() 方法

 

第 2 步  进入AbstractBeanFactory.java 的 doGetBean() 方法 的  getSingleton()匿名内部类

第 3 步  getSingleton()方法体中

第 4 步  进入beforeSingletonCreation()方法体中,不成立

第 5 步  返回getSingleton()方法体中,创建BeanA实例,这时就会调用到匿名内部类的  return createBean(beanName, mbd, args); 方法创建BeanA实例

 

第 6 步  创建BeanA实例的过程就免了第二章已经讲解过了AbstractAutowireCapableBeanFactory.java 中  doCreateBean()方法

第 7 步  前面触发BeanB属性的实例化,这里就进行BeanB的实例化操作,BeanB的实例化过程就不赘述了

同样BeanB的实例化完成之后(重复1-6 步),这时走到了BeanB实例化的注入,又触发了BeanA属性的实例化

进入AbstractAutowireCapableBeanFactory.java 中  doCreateBean()

第 8 步  进入DefaultSingletonBeanRegistry.java 的 getSingleton(String beanName, boolean allowEarlyReference) 方法体

第 9 步   把从三级缓存中获取到的BeanA实例返回,注入到正在实例化的BeanB

之后就返回到BeanB创建的getSingleton()匿名内部类,BeanB的实例化完成

第 10 步  BeanB的实例化完成之后就会把BeanB的属性注入给BeanA ,BeanA实例化完成

第 11 步  返回到第2步的匿名内部类的getSingleton(),同理BeanB也是会走这一步的,上面没有赘述

把BeanA从当前正在实例化的对象中删除,并把BeanA实例放入一级缓存中

以上是 spring5源码解读4springIOC实例化,注入解决循环依赖 的全部内容, 来源链接: utcz.com/z/515957.html

回到顶部