Spring容器启动流程

Spring容器启动流程

Spring一些背景知识:

我们知道Spring的核心是控制反转和面向切面,而这两个核心功能是由容器实现的。

Spring容器大致分为两类:BeanFactory和ApplicationContext。BeanFactory定义了容器的基本规范,只提供了基本的依赖注入功能;而ApplicationContext在BeanFactory的基础上,提供了一些新的特性,是一种框架级别的容器。通常ApplicationContext要优于bean工厂,但它唯一缺点是内存消耗比BeanFactory大,出现这种情况是由于补充的服务。如果你的程序对于内存的使用要求非常严苛,请考虑更多使用bean factory。否则,在更多标准的应用程序中,应该使用ApplicationContext。

BeanDefinition:抽象了对Bean的定义(各个属性,类名,类型,是否单例),是对依赖关系的抽象,也是实现实现依赖注入的核心数据结构。

Spring容器原理

Spring容器的原理就是反射。我们在配置文件里配置类名称,然后Spring容器根据类名称,反射生成类的实例,并调用set方法进行依赖注入。所以Spring的启动流程,其实也就是配置文件或者说BeanDefinition的定位、加载、解析、注册的过程。

Spring容器启动流程大致分为以下三个过程:

  1. 定位BeanDefinition
  2. 载入BeanDefinition
  3. 注册BeanDefinition

观察容器启动流程的姿势:代码+debug,代码入口下图

一、定位BeanDefinition

与BeanDefinition操作相关的两个类:BeanDefinitionReader和Resource。

  • Resource是Spring用来封装I/O操作的类,用来处理使用xml方式定义的BeanDefinition

  • BeanDefinitionReader:Resource不能由factory直接使用,而使用BeanDefinitionReader来对这些信息进行处理

FileSystemXmlApplicationContext构造方法:a.创建新的FileSystemXmlApplicationContext b.从指定的xml中加载definitions c.创建所有的单例。从注释中也可以看出,loading all bean definitions放在refresh函数中,所以,重点关注refresh()

refresh的主要实现:关闭之前的beanFactory;创建beanFactory,默认是DefaultListableBeanFactory;加载beanDefinitions;我们继续关注loadBeanDefinitions方法

通过XmlBeanDefinitionReader来loadBeanDefinitions;代码如下:

1
AbstractBeanDefinitionReader中loadBeanDefinitions的实现

我们来看一下是如何获得Resources:不同locationPattern,如classpath:*、class:,分别对应不同的获得方式

locationPattern为classPath:的处理方式:

二、载入BeanDefinition:

把定义的BeanDefinition转换成Spring内部表示的数据结构。

具体的载入过程如下:将xml解析为document对象;将document对象解析为bean

这个document对象究竟是什么呢?它是HTML或XML树,用来表示HTML或XML文档,并可以管理、访问节点、元素、属性等

接下来是将Document里的bean definition解析、注册;解析的结果是生成BeanDefinitionHolder。BeanDefinition是BeanDefinition对象的封装类,封装了BeanDefinition,Bean的名字和别名,用它来向IoC容器注册

对import、alias、bean标签解析。

最后生成的beanHolder,如下:

三、注册BeanDefinition

经过上面两步,已经将xml配置文件进行了定位、解析,并转换为容器内部的数据结构。但是,这些数据结构,现在还不能直接使用,需要进行注册。所谓注册,其实就是将beanDefinition放到hashMap中去,以便进行检索和使用。容器的作用就是对这些信息进行处理和维护。