1000行代码读懂Spring(一)- 实现一个基本的IoC容器

感谢原文作者,原文地址是:https://my.oschina.net/flash…

感谢原文作者,原文地址是:https://my.oschina.net/flashsword/blog/192551

最近在读Spring源码,但是Spring代码层次嵌套太多,读起来有很大跳跃性,我有个朋友甚至开玩笑说,读Spring得拿纸笔,把方法和层次都写下来。

其实Spring我已经接触很久了,记得大学有个老师说过:“学一门技术,最好是先思考一下,如果是你,会怎么实现,再带着问题去学习它”。也有人把程序员与画家做比较,画家有门基本功叫临摹,我想程序员是不是也可以用这样的方式,学习一下世界顶级的项目的编程方法?

于是就有了tiny-spring。这个项目是从我的使用场景出发,理解Spring的功能,并且一步一步完善出来的。类和方法命名基本都是照搬Spring的,包括一些配置格式都相同。这个项目我会控制在1000行以内,但是会尽量覆盖Spring的IoC和AOP核心功能。

tiny-spring是逐步进行构建的,里程碑版本我都使用了git tag来管理。例如,最开始的tag是step-1-container-register-and-get,那么可以使用

来获得这一版本。

并且为了更好的学习作者的文章,我会在后边几篇博客中,详细的对每个版本进行分析实现。

这次主要是学习IoC部分,以下是各版本的记录:

1.step1-最基本的容器

IoC最基本的角色有两个:容器(BeanFactory)和Bean本身。这里使用BeanDefinition来封装了bean对象,这样可以保存一些额外的元信息。测试代码:

2.step2-将bean创建放入工厂

step1中的bean是初始化好之后再set进去的,实际使用中,我们希望容器来管理bean的创建。于是我们将bean的初始化放入BeanFactory中。为了保证扩展性,我们使用Extract Interface的方法,将BeanFactory替换成接口,而使用AbstractBeanFactoryAutowireCapableBeanFactory作为其实现。"AutowireCapable"的意思是“可自动装配的”,为我们后面注入属性做准备。

3.step3-为bean注入属性

这一步,我们想要为bean注入属性。我们选择将属性注入信息保存成PropertyValue对象,并且保存到BeanDefinition中。这样在初始化bean的时候,我们就可以根据PropertyValue来进行bean属性的注入。Spring本身使用了setter来进行注入,这里为了代码简洁,我们使用Field的形式来注入。

4.step4-读取xml配置来初始化bean

这么大一坨初始化代码让人心烦。这里的BeanDefinition只是一些配置,我们还是用xml来初始化吧。我们定义了BeanDefinitionReader初始化bean,它有一个实现是XmlBeanDefinitionReader

5.step5-为bean注入bean

使用xml配置之后,似乎里我们熟知的Spring更近了一步!但是现在有一个大问题没有解决:我们无法处理bean之间的依赖,无法将bean注入到bean中,所以它无法称之为完整的IoC容器!如何实现呢?我们定义一个BeanReference,来表示这个属性是对另一个bean的引用。这个在读取xml的时候初始化,并在初始化bean的时候,进行解析和真实bean的注入。

同时为了解决循环依赖的问题,我们使用lazy-init的方式,将createBean的事情放到getBean的时候才执行,是不是一下子方便很多?这样在注入bean的时候,如果该属性对应的bean找不到,那么就先创建!因为总是先创建后注入,所以不会存在两个循环依赖的bean创建死锁的问题。

6.step6-ApplicationContext登场

现在BeanFactory的功能齐全了,但是使用起来有点麻烦。于是我们引入熟悉的ApplicationContext接口,并在AbstractApplicationContextrefresh()方法中进行bean的初始化工作。

是不是非常熟悉?至此为止,我们的tiny-spring的IoC部分可说完工了。这部分的类、方法命名和作用,都是对应Spring中相应的组件。虽然代码量只有400多行,但是已经有了基本的IoC功能!

项目地址

本文来自网络,不代表软粉网立场,转载请注明出处:https://www.rfff.net/p/4212.html

作者: HUI

发表评论

您的电子邮箱地址不会被公开。

返回顶部