从网上看到一篇博文 徒手撸框架–实现IoC ,写得很棒,作者抛开了 Spring 源码中复杂的校验,拓展等功能,实现了一个极简的 IoC 框架,让 Spring 源码初学者可以清楚的看到 IOC 的实现流程。
本文就借其框架,略加改造,再次介绍一下 Spring 是如何处理循环依赖的。
了解本项目核心代码需要先参考原作者的博文 徒手撸框架–实现IoC 。
# 循环依赖
其实很好理解,A 类依赖 B,B 又依赖 A。
说具体点就是 ,我们要 getBean(“a”), A 在实例化时需要为类型为 B 的成员变量赋值,因此去 getBean(“b”),而 getBean(“b”) 的时候又需要为其类型为A 的成员变量赋值,此时又会回过头去实例化 A ,导致无限循环。
用代码展示就是
|
|
# 代码改造
最主要的代码改造在于 BeanFactoryImpl 内, 添加了成员变量
|
|
用于缓存正在创建中的,提前暴露出来的单例 bean。
在获取 bean 时,会在创建之前先从此 Map 中尝试获取,而这就是解决循环依赖的关键。
以上面的例子来说,就是一开始 getBean(“a”) 时,将未完成的 a 放入缓存,getBean(“b”) 时,需要去获取 a ,会从缓存中获取,而不是再去实例化 a。
|
|
# Q & A
Q: 构造器循环依赖为什么无法解决?
A: 从上面代码可以看出,需要在 createBean 之后,才能将其放入缓存,而构造过程是在 createBean 之内的,此时尚未构造好一个基本的 bean ,拿什么放入缓存呢?
# 心得
上面只贴了 getBean 的代码,仅仅修改了原作者不到 10 行代码,其实在修改原框架,实现我们要的功能时不止这么多,包括调整对 json 的解析,对 bean 的填充等。
感受到 Spring 框架真的是很复杂很全面,这复杂程度靠说是说不清楚的,也不是翻一遍书看看源码就能明白的。而且看源码其实还是似懂非懂,中间的细节迷迷糊糊就可能跳过去了。
在追随 Spring 脚步,复现其代码的时候,才更深刻的理解其中很多操作,很多类的作用。比如说 BeanDefinition, BeanWrapper , PropertyDescriptor 这些类在我想要实现一些功能的时候才能体会到 Spring 创造它们的重要性。