IOC高级-Bean与BeanDefinition
IOC高级-Bean与BeanDefinition

BeanDefinition概述
BeanDefinition 也是一种配置元信息,它描述了 Bean 的定义信息。
bean 的定义信息可以包含许多配置信息,包括构造函数参数,属性值和特定于容器的信息,例如初始化方法,静态工厂方法名称等。子 bean 定义可以从父 bean 定义继承配置数据。子 bean 的定义信息可以覆盖某些值,或者可以根据需要添加其他值。使用父 bean 和子 bean 的定义可以节省很多输入
bean 的定义信息也是有层次性的(联想 BeanFactory 的层次性),bean 的定义信息可以继承自某个已经有的定义信息,并覆盖父信息的一些配置值。
BeanDefinition接口的方法定义
BeanDefinition 整体包含以下几个部分:
- Bean 的类信息 - 全限定类名 ( beanClassName )
- Bean 的属性 - 作用域 ( scope ) 、是否默认 Bean ( primary ) 、描述信息 ( description ) 等
- Bean 的行为特征 - 是否延迟加载 ( lazy ) 、是否自动注入 ( autowireCandidate ) 、初始化 / 销毁方法 ( initMethod / destroyMethod ) 等
- Bean 与其他 Bean 的关系 - 父 Bean 名 ( parentName ) 、依赖的 Bean ( dependsOn ) 等
- Bean 的配置属性 - 构造器参数 ( constructorArgumentValues ) 、属性变量值 ( propertyValues ) 等
由此可见,BeanDefinition 几乎把 bean 的所有信息都能收集并封装起来,可以说是很全面了。
:star::star::star::star::star:面试题:概述BeanDefinition
BeanDefinition 描述了 SpringFramework 中 bean 的元信息,它包含 bean 的类信息、属性、行为、依赖关系、配置信息等。BeanDefinition 具有层次性,并且可以在 IOC 容器初始化阶段被 BeanDefinitionRegistryPostProcessor 构造和注册,被 BeanFactoryPostProcessor 拦截修改等。
BeanDefinition的结构

AttributeAccessor
属性的访问器:定义用于将元数据附加到任意对象,或从任意对象访问元数据的通用协定的接口。
总结出第一个 BeanDefinition 的特征:**BeanDefinition 继承了 AttributeAccessor 接口,具有配置 bean 属性的功能。**
BeanMetadataElement
存放了 bean 的元信息, 只有一个方法,是获取 bean 的资源来源
1 | public interface BeanMetadataElement { |
资源来源,说白了,就是 bean 的文件 / url 路径。咱们前面写的所有示例,都是在本地磁盘上的 .class 文件加载进来的,所以对应的也就应该是 FileSystemResource
AbstractBeanDefinition
到了 BeanDefinition 的第一个实现类了,作为 BeanDefinition 的抽象实现,它里面已经定义好了一些属性和功能(大部分都有了),大体包含以下内容:(只挑选部分重要属性):
1 | // bean的全限定类名 |
GenericBeanDefinition
又看到 Generic 了,它代表着通用、一般的,所以这种 BeanDefinition 也具有一般性。GenericBeanDefinition 的源码实现非常简单,仅仅是比 AbstractBeanDefinition 多了一个 parentName 属性而已。
由这个设计,可以得出以下几个结论:
AbstractBeanDefinition已经完全可以构成BeanDefinition的实现了GenericBeanDefinition就是AbstractBeanDefinition的非抽象扩展而已GenericBeanDefinition具有层次性(可从父BeanDefinition处继承一些属性信息)
RootBeanDefinition与ChildBeanDefinition
root 和 child ,很明显这是父子关系的意思了呀。对于 ChildBeanDefinition ,它的设计实现与 GenericBeanDefinition 如出一辙,都是集成一个 parentName 来作为父 BeanDefinition 的 “指向引用” 。不过有一点要注意, ChildBeanDefinition 没有默认的无参构造器,必须要传入 parentName 才可以,但 GenericBeanDefinition 则有两种不同的构造器。
AnnotatedBeanDefinition
它可以把 Bean 上的注解信息提供出来
基于@Component的BeanDefinition
给 Person 上打一个 @Component 注解,然后使用 AnnotationConfigApplicationContext 来驱动扫描 Person 类
1 | public class BeanDefinitionQuickstartComponentApplication { |
基于 xml 解析出来的 bean ,定义来源是 xml 配置文件;基于 @Component 注解解析出来的 bean ,定义来源是类的 .class 文件中。
基于@Bean的BeanDefinition
编写一个配置类 BeanDefinitionQuickstartConfiguration ,使用 @Bean 注册一个 Person :
1 | java复制代码 |
之后,使用这个配置类驱动 IOC 容器,并直接获取 BeanDefinition :
1 | java复制代码public class BeanDefinitionQuickstartBeanApplication { |
具体区别可以发现有这么几个:
- Bean 的类型是 Root bean (
ConfigurationClassBeanDefinition继承自RootBeanDefinition) - Bean 的 className 不见了
- 自动注入模式为
AUTOWIRE_CONSTRUCTOR(构造器自动注入) - 有 factoryBean 了:person 由
beanDefinitionQuickstartConfiguration的person方法创建
:star::star::star:【原理】BeanDefinition是如何生成的(简易理解)
- 通过 xml 加载的
BeanDefinition,它的读取工具是XmlBeanDefinitionReader,它会解析 xml 配置文件,最终来到DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions方法,根据 xml 配置文件中的 bean 定义构造BeanDefinition,最底层创建BeanDefinition的位置在org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition。 - 通过模式注解 + 组件扫描的方式构造的
BeanDefinition,它的扫描工具是ClassPathBeanDefinitionScanner,它会扫描指定包路径下包含特定模式注解的类,核心工作方法是doScan方法,它会调用到父类ClassPathScanningCandidateComponentProvider的findCandidateComponents方法,创建ScannedGenericBeanDefinition并返回。 - 通过配置类 +
@Bean注解的方式构造的BeanDefinition最复杂,它涉及到配置类的解析。配置类的解析要追踪到ConfigurationClassPostProcessor的processConfigBeanDefinitions方法,它会处理配置类,并交给ConfigurationClassParser来解析配置类,取出所有标注了@Bean的方法。随后,这些方法又被ConfigurationClassBeanDefinitionReader解析,最终在底层创建ConfigurationClassBeanDefinition并返回。