Spring:SpringIoC 大致流程

SpringIoC
是什么?
官方文档的解释是:IoC 也称为依赖注入(DI)。在此过程中,对象仅通过构造函数参数,工厂方法的参数或在构造或从工厂方法返回后在对象实例上设置的属性来定义其依赖项(即,与它们一起使用的其他对象) 。然后,容器在创建 bean 时注入那些依赖项。从本质上讲,此过程是通过使用类的直接构造或诸如服务定位器模式之类的机制来控制其依赖关系的实例化或位置的 Bean 本身的逆过程(因此,其名称为 Control Inversion)。
简单来说:就是我们将一个个的 bean 对象交给 IoC 去管理,他会帮助我们去创建对象实例、填充属性、初始化、添加监听器等过程。
类图
我们以常用的 ClassPathXmlApplicationContext 为例

大致过程

首先,一个 IoC 容器应创建一个工厂(DefaultListableBeanFactory),可以使我们读取的资源文件可以存放。
然后,将配置文件通过一个规范(BeanDefinitionReader)加载出来。
接着,是 bean 对象实例化之前的一些准备(初始化啊、事件处理器、注册组件等);例如上图中的 BeanFactoryPostProcessor、多播器等。
重要的地方来了,创建一个个的非懒加载的成品 Bean 对象(finishBeanFactoryInitialization 方法)。
最后,是一些事件的发布、缓存、销毁等。
源码分析
从 ClassPathXmlApplicationContext 开始分析。在它的构造方法中,我们可以看见调用了父类(AbstractApplicationContext 类)的构造方法、设置配置文件的加载路径以及核心方法 refresh()方法。

父类 AbstractApplicationContext 的构造方法

setConfigLocations()方法

接下来,我们进入核心方法 refresh()。

我们重点看序号 2 和序号 11,其他有兴趣可以自己点进去看看。
obtainFreshBeanFactory()方法

跟进 refreshBeanFactory()方法,在 AbstractRefreshableApplicationContext 类中可以找到 refreshBeanFactory()这个方法

createBeanFactory()方法中

loadBeanDefinitions()方法,也是委派给子类去实现。

我们进去子类 AbstractXmlApplicationContext 类的 loadBeanDefinition()方法。在这里进行了配置文件读取规范的定义,我们继续跟进 loadBeanDefinitions()方法。

loadBeanDefinitions()方法。传入的可能是个 String[]或者 Resource[]类型。但是大致流程都差不多:String[]->String->Resource[]->Resource->Document->BeanDefinition。这里就不过多深入了,感兴趣可以照这个流程看下去。

资源文件加载完成后,我们的 BeanFactory 差不多就创建好了。接着,我们到 IoC 最重要的过程,Bean 对象(不是懒加载的)的实例化和初始化。这里为什么将实例化和初始化分开说呢,是想更好地帮助理解 Bean 对象的创建过程。其实 Spring 中更加的细分了一下,分成了实例化(createBeanInstance()方法)、填充属性(populateBean()方法)和初始化(initializeBean()方法)。
实例化:在堆中开辟了一块空间。属性都是系统默认值。
初始化:给属性完成具体的赋值操作,调用具体的初始化方法。
好了,我们进入 finishBeanFactoryInitialization()方法,里面你会看到一些对 beanFactory 的属性设置,其中重点的是 preInstantiateSingletons()方,点进去,它会调用 DefaultListableBeanFactory 的 preInstantiateSingletons()方法。

我们可以看到 getBean()方法,这里就是准备开始进行 bean 对象的创建了。点进去,我们可以看真正执行的是 doGetBean()方法

doGetBean()方法,就是根据不同的 Bean 采用不同的创建策略。1. 如果 Bean 是单例的,则在容器创建之前先从缓存中查找,确保整个容器只存在一个实例对象 2. 如果 Bean 是原型模式的,则容器每次都会创建一个新的实例对象 3. 指定了 Bean 的生命周期


我们进入 createBean(),发现还有一个 doCreateBean 方法(),终于,我们到了真正创建 Bean 对象的方法。点进去。

我们发现我们终于找到了之前所说的那三个方法了,创建、填充和初始化。
createBeanInstance()方法返回的是一个 BeanWrapper,bean 的封装类。
populateBean()则是将 bean 的一些属性字段进行解析、填充。
在 initializeBean()中

到此,我们一开始的流程图所有的地方差不多都完成了。其中有些细节方面没点进去看看,主要是大致了解 IoC 的过程。可以自行 debug 进去看看。
原文链接:https://www.cnblogs.com/zhaomomo/p/14704338.html
如果觉得本文对你有帮助,可以关注一下我公众号,回复关键字【面试】即可得到一份 Java 核心知识点整理与一份面试大礼包!另有更多技术干货文章以及相关资料共享,大家一起学习进步!

版权声明: 本文为 InfoQ 作者【Java王路飞】的原创文章。
原文链接:【http://xie.infoq.cn/article/5f84059d0edd7c539bf687970】。未经作者许可,禁止转载。
评论