MENU

Spring 容器的基本实现

July 27, 2019 • Read: 127 • Java

标题

首先我们先看一段测试代码

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
MyTestBean bean = bf.getBean("myTestBean");

你可以把BeanFactory当做ApplicationContext理解,因为平常我们多数用的都是ApplicationContext。那么上面的代码做了哪些工作呢?从代码字面意思我们可以理解成以下几点。

  • 读取beanFactoryTest.xml配置文件;
  • 根据配置文件的内容进行实例化bean
  • 调用实例化后的实例。

接下来开始我们的源码学习之路,在开始之前,我们先来了解Spring中核心的两个类。

1. DefaultListableBeanFactory

直接上类图

DefaultListableBeanFactory

DefaultListableBeanFactory是整个bean加载的核心部分,是 Spring 注册及加载bean的默认实现类,承担了bean的注册管理工作。XmlBeanFactory继承自DefaultListableBeanFactory并对其进行拓展,唯独与父类不同的个性化实现是增加了XmlBeanDefinitionReader类型的reader属性。在XmlBeanFactory中使用reader属性对资源文件进行读取和注册。

通过这个类图可以清晰的了解到DefaultListableBeanFactory的脉络,其中各个类的作用简单的介绍如下:

由于类比较多,刚接触的人会看的比较懵,所以我空格和*号做了标记。*为类,其他为接口,空格分开作为一个体系

AliasRegistry// 定义对alias简单增删改操作
SimpleAliasRegistry// *AliasRegistry的实现类,增加使用map作为alias的缓存

SingletonBeanRegistry// 定义对单例bean的注册及获取
DefaultSingletonBeanRegistry// *SingletonBeanRegistry的实现类且继承SimpleAliasRegistry
FactoryBeanRegistrySupport// *在DefaultSingletonBeanRegistry基础上增加对FactoryBean的特殊处理功能

BeanFactory // 主要包含getBean、containBean、getType、getAliases等管理bean的方法;
HierarchicalBeanFactory// extends BeanFactory,增加了对parentFactory的支持
ConfigurableBeanFactory// extends HierarchicalBeanFactory,提供配置Factory的各种方法
AbstractBeanFactory// *综合FactoryBeanRegistrySupport和ConfigurableBeanFactory的功能
AbstractAutowireCapableBeanFactory// *综合AbstractBeanFactory并实现AutowireCapableBeanFactory

BeanDefinitionRegistry// BeanDefinition的增删改操作且继承AliasRegistry

AutowireCapableBeanFactory// 创建bean、自动注入、初始化及应用bean的后处理器
ListableBeanFactory// 根据各种条件获取bean的配置清单
ConfigurableListableBeanFactory// BeanFactory配置清单,指定忽略类型及接口等

DefaultListableBeanFactory// *综合以上功能,主要是对bean注册后的处理

2. XmlBeanDefinitionReader

上文我们提到了XmlBeanDefinitionReader,xml配置文件读取是Spring中重要的部分,大部分功能都是以配置作为切入点,接下来从XmlBeanDefinitionReader中梳理一下资源文件读取、解析及注册的大致流程,首先看一下涉及各个类的功能。

请输入图片描述

BeanDefinition // 容器中的每一个bean都会有一个对应的BeanDefinition实例,该实例负责保存bean对象的所有必要信息,包括bean对象的class类型、是否是抽象类、构造方法和参数、其它属性等等。
ResourceLoader // 资源加载器
BeanDefinitionReader // 读取资源并转换成BeanDefinition
EnvironmentCapable // 获取Environment 
DocumentLoader // 资源文件加载转换为Document
AbstractBeanDefinitionReader // 实现BeanDefinitionReader、BeanDefinitionReader
BeanDefinitionDocumentReader // 读取Document并注册BeanDefinition
BeanDefinitionParserDelegate // 定义解析Element的各种方法

XmlBeanDefinitionReader读取xml配置文件的大致流程为:

  • 通过AbstractBeanDefinitionReader 中的方法,使用ResourceLoader将配置文件转换为Resource文件。
  • 通过DocumentLoaderResource文件转换为Document文件
  • 通过实现BeanDefinitionDocumentReaderDefaultBeanDefinitionDocumentReader类对Document进行解析,并使用BeanDefinitionParserDelegateElement进行解析

标题二

到这里我们已经对Spring容器有了大概的了解,截下来我们要分析以下功能的实现:

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

我们通过下面的时序图来了解一下上面的代码逻辑;

请输入图片描述

通过时序图我们可以看到整个函数的逻辑处理顺序,

  • 首先调用ClassPathResource的构造方法,将配置文件beanFactoryTest.xml转化为Resource实例对象,我得理解是外部资源加载;
  • 初始化XmlBeanFactory,这个过程中又经过很多操作将Resource对象转化成我们需要的bean
    Resource资源加载的源码解析可以看这篇《IoC - 统一资源加载策略详解》

有了Resource后,我们跟着源码继续探寻XmlBeanFactory的初始化过程,我们先看XmlBeanFactory代码。

// XmlBeanFactory.java
// 构造方法内部继续调用内部构造方法
public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        super(parentBeanFactory);
        this.reader.loadBeanDefinitions(resource);
    }

我们可以看出#this.reader.loadBeanDefinitions(resource) 才是资源加载的真正实现,是Spring容器中特别重要的一步,所以单独写了一篇文章,装载BeanDefinition源码解析详见《IoC - 解析及注册 BeanDefinitions》