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进去看看。

最新文章

  1. ,net core mvc 文件上传
  2. 【Winform】使用BackgroundWorker控制进度条显示进度
  3. Windows 10家庭版共享打印机
  4. hadoop安装遇到的各种异常及解决办法
  5. JS魔法堂:那些困扰你的DOM集合类型
  6. iOS 学习笔记 七 (2015.03.29)code snippet操作
  7. 10个你能参与并学习的Java开源项目
  8. 使用Powershell在Microsoft Azure中创建Virtual Machine
  9. Linux Shell编程(19)——测试与分支
  10. linux脚本错误: line *: [: missing `]'
  11. 使用ioctl向linux内核传递参数的方法实例
  12. My first_leetcode_Rever Ingeter 数字翻转java实现(办法集合)
  13. AngularJS学习笔记之directive——scope选项与绑定策略
  14. Mybatis下的sql注入
  15. .Net Core 项目在Windows服务中托管【转载】
  16. android开发学习——day8
  17. 使用json-server模拟REST API
  18. IO 多路复用是什么意思?
  19. 关于Floyd求解最小环的问题
  20. JNI 在命令行窗口输入字符,不显所输入字符,显指定的掩饰符

热门文章

  1. Spark和Spring整合处理离线数据
  2. (原创)用.NET Core实现微信自动回复工具(上篇)
  3. jdbc连接数据库(oracle、mysql)
  4. 代理模式详解:静态代理、JDK动态代理与Cglib动态代理
  5. 【odoo14】第十三章、网站开发(对外服务)
  6. NIO三大组件之Selector选择器
  7. 开发C语言的3款神器,VS2019、VScode和IntelliJ Clion
  8. 找单词 HDU - 2082(普通母函数)
  9. P1996_约瑟夫问题(JAVA语言)_可能是最简单的解法了!
  10. kthread_worker和kthread_work机制