Spring原理

Tiny-Spring源码阅读

导读:很想仔细了解 Spring IOC/AOP 框架,但发现 Spring 源码不仅长且难以阅读。今天搜索时发现 github 上有一个高星重制 Spring IOC/AOP 框架的项目——Tiny-Spring,粗略阅读一遍大概30分钟,仔细研究一番很有收获,特此记录。

总体结构

us.codecraft.tinyioc 下有三个包,aop beans contextaop 毫无疑问是对面向切面编程的实现,beanscontext 用于实现 IOC框架。

启动分析

  1. ApplicationContext context = new classPathXmlApplicationContext('ioc.xml');

    说明:创建上下文对象,程序入口。继承关系:[I]BeanFactory<--[I]ApplicationContext <-- [AbsC]AbstractApplicationContext <-- [C]ClassPathXmlApplicationContext

  2. this(configLocation, new AutowireCapableBeanFactory());

    调用默认构造方法。

    Beanfactory系列继承关系:

    [I]BeanFactory <-- [AbsC]AbstractBeanFactory <-- [C]AutowireCapableBeanFactory

  3. 【返回3】调用另一个构造方法。

    第一句。调用父级构造方法,具体:this.beanFactory = beanFactory; 将刚创建的beanFactory赋值到protected属性中。

    第二句。xml文件路径赋值给自身属性。

    第三句。刷新,方法定义在父级中,被子级继承。具体操作:

  4. 【返回 4】先看第一句loadBeanDefinitions,方法原型在AbstarctApplicationContext中,是抽象方法,此方法在子类被 override:

  5. 【返回5】步骤1,创建ResourceLoader,并以此为参数创建XmlBeanDefinitionReader

    ResourceLoader 定义如下,其唯一方法用于根据文件位置读取资源。

    XmlBeanDefinitionReader 的构造方法:

    XmlBeanDefinitionReader 的父类是 AbstractBeanDefinitionReader,其构造方法:

    其中 registry 是一个 HashMap ,用于保存 bean 名(具体指xml中的id属性)和它的定义 beanDefinition

    beanDefinition 具体如下:

     

  6. 【返回5】现在负责读取Xml的对象准备好了,调用 loadBeanDefinition ,然后调用接下来的一连串方法:

    初步读下来,概括如下:读取xml文件,创建xml解析树,把xml中的元素解析后注册到 registry 中。

  7. 【返回5】

    for-each 循环遍历哈希表 registry,对于其中的每个 key-value 对,在 beanFactory 中预注册 bean

  8. 【返回8】

    这里需要提一下,AbstractBeanFactory 包含三个重要变量:

    调用 registerBeanDefinition ,类似把半成品 registry 搬到了 context 中。

  9. 【返回4】

    bean 信息处理完毕,调用 onRefresh()

    试图取得 bean,但由于 bean 未创建,因此得到 null ,调用创建 bean 的方法:

    至于为什么要先 getBean,是因为onFresh可以在后面被反复调用(初始化时固然得到的 bean 全为 null),且这是在创建 singleton,onFresh 方法如果在初始化完毕后再次调用,如果没有 getBean,则新创建出的 bean 覆盖原来的 bean,就产生了矛盾。

  10. 【返回10】

    先创建 bean ,注册到 beanDefinitionMap 然后按序调用 beanPostProcessor

    至此 applicationContext 的 Bean 管理已经建立起来,可以做到随时取用了。

流程总结

  1. 初始化 ApplicationContext ,在此过程中创建 BeanFactory 的子类作为它的私有属性。
  2. beanFactory 创建 xml 解析对象,解析指定路径的xml,并将信息注册到解析器的哈希表 registy 中。
  3. xml解析器生产出的半成品 registry 信息搬入 beanFactory 的总管理对象 beanDefinitionMap 中。
  4. 对于其中的每一个 项目,创建 Bean 并调用后置处理器。
  5. 创建完毕,在 context 中可调用 getBean 连接到 beanFactory,并拿到 Bean

学习心得

  1. applicationContext 虽然能对 bean 进行相关操作,但它只不过是一个存放了 beanFactory 对象的平台, 而 beanFactory 则是负责解析 bean,生产 bean 等幕后工作。可以直接创建 applicationContext 管理 bean,也可以创建 beanFactory 管理,一般选择前者。
  2. 此项目充分展示了 Java 面向对象设计的范例:任何体系都存在 Interface,AbstarctClass,Class逐级继承,并存在多接口实现和接口继承,值得学习。
  3. (推测)SpringBoot 的启动也是类似的过程,SpringBoot 的 bean 取得方式有 xml 和 annotation 两种,这两种方法只是解析时的步骤略有差异,其对 bean 的注册等管理操作应该是一致的。