1. 引言
在进入Spring源码分析之前,我们先来看一下Spring框架的总体结构。如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/787be8ee139339d004ecabe98075fae3.png)
Spring作为一个分层框架,通过划分多个模块,提供了一系列的功能要素。这些模块基于Core Container(核心容器)构建。本篇围绕Core Container的基础Beans和Core两个模块展开,它们提供了IoC(Inversion of Control控制反转)/DI(Dependency Injection依赖注入)的特性。Core模块提供了Spring框架基本的核心工具类,Beans模块提供了创建和管理bean以及Ioc和DI的相关操作。
在本篇的内容主要是基于以XML配置Bean的方式来探究Bean的解析与注册。
2. 初识Bean的解析与注册
以XML配置文件的方式,Spring框架中对Bean的创建大致流程主要包括:
- 获取xml配置文件Resource资源;
- 将配置文件Resource转换为Document对象;
- 将Document解析为BeanDefinition,BeanDefinition是bean实例的抽象描述,也是我们要讲述的核心,所谓Bean的解析与注册,其实就是对BeanDefinition的一系列操作;
- 将BeanDefinition注册缓存到一个Map(beanDefinitionMap)中;
通过Map中的BeanDefinition我们就可以实现后续对Bean的创建和管理等操作,后面我们会逐步展开剖析。本篇关注的焦点在于Spring如何一步步实现从XML配置到BeanDefinition的Map注册。
2.1. Xml配置文件Resource资源获取
Spring对资源的获取提供了多种方式,这里我们通过Resource接口来获取资源,由于Spring的xml配置文件一般放在类路径下,所以我们使用ClassPathResource来实现。
Resource resource = new ClassPathResource("conf/beans.xml");
配置文件beans.xml的内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="person" class="com.yanglh.beans.Person">
<constructor-arg name="age" value="29"/>
<constructor-arg name="fullname" value="yangliehui" />
</bean>
</beans>
得到了Resource对象我们就可以读取资源的内容和相关属性信息。关于Spring的ClassPathResource提供的相关功能方法请参考Spring ClassPathResource详解。
2.2. 认识DefaultListableBeanFactory
DefaultListableBeanFactory是Spring中bean加载的核心处理类,是注册和加载bean的默认实现,其类图如下:
![](https://i-blog.csdnimg.cn/blog_migrate/0e2a29c355402c4a42d94da6940a0f6d.png)
从上图中我们大致可以看到DefaultListableBeanFactory继承了父类/接口的两大基因,分别是XxxBeanFactory和XxxRegistry(这里的重点是BeanDefinitionRegistry)。如果对这两个基因大致概括一下的话,那么XxxRegistry是用来注册和存储管理BeanDefinition(由BeanDefinitionRegistry定义)和bean对象(由XxxBeanRegistry定义)的,其中BeanDefinitionRegistry定义了将BeanDefinition实例缓存于一个Map中的方法。BeanFactory是Bean工厂,用来生产Bean的,我们可以从BeanFactory中获取我们交给Spring管理的Bean对象。
2.3. 认识XmlBeanDefinitionReader
Xml / BeanDefinition / Reader三个关键字,Xml我们已经知道,就是我们的Bean配置文件。BeanDefinition是Spring中管理的Bean的抽象定义,用来描述Bean对象的。那么Reader是什么?从Xml中读取解析注册BeanDefinition的读取器,负责将Xml资源转换为Document对象、加载BeanDefinition、注册BeanDefinition等,是整个BeanDefinition创建过程中的读取调度中心。
如果我们把从XxxBeanFactory中getBean得到的对象看成是产品成品的话,那么Resource就是物料清单,XxxReader就是根据将物料清单转换为实际成品原材料BeanDefinition的加工处理调度中心,BeanDefinitionRegistry就是实际成品原材料BeanDefinition进行存储和管理的仓库,XxxBeanFactory就是根据原材料生产和管理产品成品(Bean对象)的工厂。
![](https://i-blog.csdnimg.cn/blog_migrate/bc5f2bdd2835e9139dc55a2fab3c4991.png)
用代码实现如下:
// 创建Resource物料清单
Resource resource = new ClassPathResource("conf/beans.xml");
// 创建DefaultListableBeanFactory(含有XxxRegistry和XxxBeanFactory两大基因)
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
/**
创建BeanDefinition读取器(BeanDefinition加工处理中心)。并将含有
XxxRegistry基因的DefaultListableBeanFactory注入,用来存储管理BeanDefinition。
从XmlBeanDefinitionReader的构造方法:
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry)中
我们也能看到它的确需要注入的就是一个Registry。
*/
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
/**
万事都已俱备,下面我们可以拿着Resource物料清单
到BeanDefinition加工处理中心(XxxReader)中
来生产Beandefinition了
*/
reader.loadBeanDefinitions(resource);
// 从Bean工厂中得到我们的Bean成品
Person person = factory.getBean("person",Person.class);
注:以上我们把Bean从xml配置到实际得到Bean对象的流程做了一个大概的抽象的了解,这有助于我们对Spring的这一流程有一个全貌的认识。其实Spring内部做了大量的操作完成了这一流程,有些表述可能并不精确,但是没有关系,接下来我们会走进Spring的源码,以源码精确的理解,去完善丰富和修正我们上面的描述。