|Spring循环依赖,我本来都不想写的,但网上好多错误观点( 二 )
明确了上面这三点 , 再结合我上面说的“不完整的” , 我们来理一下 。
如果全是构造器注入 , 比如A(B b) , 那表明在 new 的时候 , 就需要得到 B , 此时需要 new B。
但是 B 也是要在构造的时候注入 A, 即B(A a) , 这时候 B 需要在一个 map 中找到不完整的 A, 发现找不到 。
为什么找不到?因为 A 还没 new 完呢 , 所以找到不完整的 A ,因此如果全是构造器注入的话 , 那么 Spring 无法处理循环依赖。
一个set注入 , 一个构造器注入一定能成功?假设我们 A 是通过 set 注入 B , B 通过构造函数注入 A , 此时是 成功的。
我们来分析下:实例化 A 之后 , 可以在 map 中存入 A , 开始为 A 进行属性注入 , 发现需要 B 。
此时 new B , 发现构造器需要 A , 此时从 map 中得到 A, B 构造完毕 。
B 进行属性注入 , 初始化 , 然后 A 注入 B 完成属性注入 , 然后初始化 A 。
整个过程很顺利 , 没毛病 。
假设 A 是通过构造器注入 B , B 通过 set 注入 A , 此时是 失败的。
我们来分析下:实例化 A , 发现构造函数需要 B ,此时去实例化 B 。
然后进行 B 的属性注入 , 从 map 里面找不到 A , 因为 A 还没 new 成功 , 所以 B 也卡住了 , 然后就 gg 。
看到这里 , 仔细思考的小伙伴可能会说 , 可以先实例化 B 啊 , 往 map 里面塞入不完整的 B , 这样就能成功实例化 A 了啊 。
确实 , 思路没错 但是 Spring 容器是按照字母序创建 Bean 的 , A 的创建永远排在 B 前面。
现在我们总结一下:
- 如果循环依赖都是构造器注入 , 则失败
- 如果循环依赖不完全是构造器注入 , 则可能成功 , 可能失败 , 具体跟BeanName的字母序有关系 。
明确了 Spring 创建 Bean 的三步骤之后 , 我们再来看看它为单例搞的三个 map:
- 一级缓存 , singletonObjects , 存储所有已创建完毕的单例 Bean (完整的 Bean)
- 二级缓存 , earlySingletonObjects , 存储所有仅完成实例化 , 但还未进行属性注入和初始化的 Bean
- 三级缓存 , singletonFactories , 存储能建立这个 Bean 的一个工厂 , 通过工厂能获取这个 Bean , 延迟化 Bean 的生成 , 工厂生成的 Bean 会塞入二级缓存
- 首先 , 获取单例 Bean 的时候会通过 BeanName 先去 singletonObjects(一级缓存) 查找完整的 Bean , 如果找到则直接返回 , 否则进行步骤 2 。
- 看对应的 Bean 是否在创建中 , 如果不在直接返回找不到 , 如果是 , 则会去 earlySingletonObjects (二级缓存)查找 Bean , 如果找到则返回 , 否则进行步骤 3
- 去 singletonFactories (三级缓存)通过 BeanName 查找到对应的工厂 , 如果存着工厂则通过工厂创建 Bean, 并且放置到 earlySingletonObjects 中 。
- 如果三个缓存都没找到 , 则返回 null 。
返回 null 之后 , 说明这个 Bean 还未创建 , 这个时候会标记这个 Bean 正在创建中 , 然后再调用 createBean 来创建 Bean , 而实际创建是调用方法 doCreateBean 。
doCreateBean 这个方法就会执行上面我们说的三步骤:
- 春天|今年春天又被《我和我的祖国》戳中了:这些脑内循环BGM你听过几首?
- 中企展开行动,降低“苹果依赖症”,央视的呼吁起效用了?
- 水循环|美媒报道:关于水的五个有趣事实
- 中企开始行动,央视呼吁降低“苹果依赖症”,有效果了?
- 京东科技与天奇股份达成深度合作 共建锂电池循环再利用平台
- 中企展开行动,降低“苹果依赖症”,央视的呼吁起效了?
- spring|苹果新款5G手机,为了赢取更大的市场,不惜拉起价格战
- spring|iPhoneX升级iOS15.4beta5:优化很棒!用着挺舒服,值得升级
- B站越来越像淘宝了,但营收依赖广告,前景够大吗?
- spring|OPPO Find X5竟然才3999元起?顿时感觉手里的三星S22不香了