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
并返回。