python ioc_Spring源码分析(三)手写简单的IOC容器和解决循环依赖问题

前言

上一节我们分析了Spring的实例化和IOC过程。在熟悉了Spring的处理流程后,我们自己能不能写一个IOC的容器和实现依赖注入呢?要注意哪些问题呢?本章节我们重点关注两个问题。

手写一个简单的IOC容器并实现依赖注入

分析Spring是怎样解决循环依赖的问题

一、加载配置文件

先来看我们自定义的配置文件,ioc.xml。我们定义了两个Bean,User和Role。

dc4b44157f0f917346384aab23327073.png

扫描方式很简单,main方法指定了XML文件的路径。获取文件的输入流,转成Document对象解析即可,这点和Spring的做法是一致的。并把property属性简单化处理,放在一个List>中。

1871fb18fc728003e3bbb958c1164b0e.png

5110185c47114a2ff261003c18b22d5d.png

二、实例化

上一步我们拿到beanName的集合,把他放入了List中。遍历它们进行实例化和依赖注入,巧了,Spring也是这样干的。只不过更复杂,更严谨。

ae36171105d78520373f44e1d16cc326.png

三、测试

进行main函数,看看测试结果。

09e1c01d8f8db9bcd4cb83003e278c32.png

输出结果如下

2340f8971aac5f69a7184c11722972bf.png

从结果来看,这两个Bean的实例化和依赖注入是没问题的,暂时完成了我们本章节提出的第一个小目标。

四、循环依赖

如果我们把配置文件改一下,让User和Role形成循环依赖呢?我们的程序还能正常吗?

怂,不敢跑。就上面的代码而言,它肯定会死循环。User依赖Role,注入的时候发现还没有Role的实例,就先去实例化Role;实例化Role的时候,又发现依赖了User,再去实例化User...好了,下面我们看下Spring是怎么解决这事的。

分析Spring之前,我们先来了解几个缓存的定义。

singletonObjects:用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用。

earlySingletonObjects:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖。

singletonFactories|:存放 bean 工厂对象,用于解决循环依赖。

singletonsCurrentlyInCreation:当前正在创建的bean的名称。

看到这几个缓存,我们可以大概理出一个思路。实例化Bean的时候,先从singletonObjects查找缓存,如果命中则返回;未命中的话先把自己放入singletonsCurrentlyInCreation中,说明自己正在创建中。

具体开始实例化。完成后,把beanName和对应的bean工厂放入singletonFactories。

依赖注入,当有循环依赖的时候,重复第1个步骤。还是从singletonObjects查找缓存,虽然还是未命中,但是通过判断singletonsCurrentlyInCreation发现Bean正在创建中。然后从singletonFactories获取bean的工厂对象,拿到该bean。然后把这个bean提前曝光,放入earlySingletonObjects。需要注意的是,此时的bean只是刚刚实例化,还未填充属性。

注入完成,循环依赖问题解决。

d47c6a8afee2c97e44ff985a8680ac70.png

基于上面的思路,我们先把上面的代码重构一下。全部代码在GitHub:手写简单IOC容器,大家可以拿下来运行一下看看。

1、还是先遍历所有的beanName

df50bd35826a3323c58077426cfab5bb.png

2、获取Bean实例

5909133399af5dd2a5bd78b6270b8e51.png

3、下面来看两个getSingleton方法。注意参数不同

632d7660db7a394440802d4da079c8d0.png

49127d0021958064b39fb21246ed9dd6.png

4、Bean的实际创建,重点是创建之前把之前放入singletonsCurrentlyInCreation,创建之后把自己的实例放入bean工厂,singletonFactories。

dacbdef8680641966ea062f25710e67f.png

5、注入属性,属性值的类型如果是ref引用类型,就再循环调用doGetBean。同一个Bean在第二次调用的时候,就会拿到工厂里提前曝光的Bean对象并返回,完成注入。

6355b7b2ccaaba4c5d2e75e8a82aae24.png

五、总结

关于循环依赖,Spring源码里处理的时候非常的绕,还有很多内部类糅杂在一块,刚开始看的我简直怀疑人生。最好先弄明白那几个缓存的含义,也可以跟着上面的代码都Debug几次,再去理解这个流程。

关于Spring源码这一块就不贴了,太分散而且太多,有兴趣的小伙伴可以自行翻阅。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值