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