Spring 源码阅读 11:BeanDefinition 介绍

之前用 5 篇源码阅读文章详细分析了 BeanFactory 初始化的过程中 BeanDefinition 加载的流程。我把这一过程分成了四个阶段,这里再做一个简单的总结。

BeanDefinition 加载过程总结

  • 在准备阶段,Spring 根据 XML 配置文件的路径,创建 Resource 对象,提供了对配置资源文件的访问。然后,再使用 EncodedResource 对资源进行封装,以添加编码和字符集特性。再之后,会将资源的输入流封装成用于 XML 解析的 InputSource 对象。这一过程参考:Spring 源码阅读 06:加载 BeanDefinition 的过程(准备阶段)
  • 在资源加载阶段,Spring 的主要工作是把上一步得到的 InputSource 和资源对象本身,交给 XML 解析器进行解析,并最终得到 Document 对象。在解析之前,Spring 准备了一些要提供给解析器的配置信息,包括自定义的 EntityReslver、错误处理逻辑、XML 文件验证模式等。这一过程参考:Spring 源码阅读 07:加载 BeanDefinition 的过程(资源加载阶段) 。关于自定义 EntityReslver 的作用和原理参考:Spring 源码阅读 10:自定义的 EntityResolver 是如何帮助 Spring 校验 XML 配置的
  • 在 BeanDefinition 解析的阶段,Spring 会把上一步加载资源得到的 Document 对象,解析成 BeanDefinition 对象。首先,会创建一个 BeanDefinitionDocumentReader 对象,并将解析任务交给这个对象。然后,BeanDefinitionDocumentReader 会创建一个 BeanDefinitionParserDelegate 对象,最终将解析的具体任务交给了 BeanDefinitionParserDelegate。解析工作的主要逻辑就是创建一个 GenericBeanDefinition 对象,并将通过 Document 对象获取到 XML 文件中配置的所有内容,为 GenericBeanDefinition 相应的属性赋值。这一过程参考:Spring 源码阅读 08:加载 BeanDefinition 的过程(解析阶段)
  • 最后就是注册 BeanDefinition 的阶段,在得到 BeanDefinition 之后,要将其注册到 Spring 的容器,也就是 BeanFactory 中。注册之前,Spring 还会对解析到的 BeanDefinition 进行检查,确保没有相互冲突的配置。确保没有问题后,将 BeanDefinition 添加到真正的容器 beanDefinitionMap 中,它是一个 ConcurrentHashMap 类型的集合。最后还会对 BeanDefinition 的别名进行检查,确保他们之间不会发生冲突和混淆。这一过程参考:Spring 源码阅读 09:加载 BeanDefinition 的过程(注册阶段)

BeanDefinition 类关系介绍

分析了这么多流程,还没有单独介绍 BeanDefinition。它是 Spring 框架中最重要的接口之一,用来表示 Spring 容器中 Bean 的定义,Spring 容器中的 Bean 都是根据 BeanDefinition 来创建的。

以下是 BeanDefinition 相关的接口和类的关系图:

Spring 源码阅读 11:BeanDefinition 介绍

之前分析的 BeanDefinition 加载流程中,创建的都是 GenericBeanDefinition 类型的 BeanDefinition。在比较早的版本中,Spring 都是使用 RootBeanDefinition 和 ChildBeanDefinition,它们分别用来创建没有parent属性和有parent属性的 Bean,在 Spring 的 2.5 版本之后,开始使用 GenericBeanDefinition,如果需要声明 BeanDefinition 之间的父子关系,可以通过setParentName方法来设置。这三个实现类表示的都是从 XML 配置中解析到的 BeanDefinition,在图中可以看到,GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition 都直接继承了 AbstractBeanDefinition。

除此之外,还有 AnnotatedGenericBeanDefinition 和 ScannedGenericBeanDefinition 两个类继承了 GenericBeanDefinition,从名字可以看出,他们表示的是通过注解和组件扫描得到的 BeanDefinition。

由此可见,在这个体系中,除了 BeanDefinition 接口之外,AbstractBeanDefinition 也是一个很重要的类,它是所有 BeanDefinition 实现类的父类。

AbstractBeanDefinition 抽象类

在 BeanDefinition 接口中,定义的都是大量属性相关的 getter 和 setter 方法,因此,我们重点看一下 AbstractBeanDefinition 中都包含哪些内容。

在 AbstractBeanDefinition 中也有大量的方法定义,不过基本也都是 getter 和 setter 方法,毕竟 BeanDefinition 表示类定义,也就是需要保存大量的实例化 Bean 的信息,比如 XML 文件中的配置信息,它的主要作用其实就是保存数据,因此,在 AbstractBeanDefinition 中声明了大量的公共属性,他们都对应着 XML 配置文件中bean标签的属性和子标签信息。

在 BeanDefinitionParserDelegate 的parseBeanDefinitionAttributes方法中也可以看出,从bean标签的属性中出来的内容也都保存在了这些属性中。

总结

本文总结了 BeanDefinition 加载的过程,并对 BeanDefinition 接口下重要的类作了介绍。BeanDefinition 中的涉及到属的性非常多,在之后的源码分析中,还会遇到,到时候再进行详细探索。