BeanDefinition概述
BeanDefinition 是一种配置元信息,它描述了 Bean 的定义信息
官方文档解释
A bean definition can contain a lot of configuration information, including constructor arguments, property values, and container-specific information, such as the initialization method, a static factory method name, and so on. A child bean definition inherits configuration data from a parent definition. The child definition can override some values or add others as needed. Using parent and child bean definitions can save a lot of typing. Effectively, this is a form of templating.
bean 的定义信息可以包含许多配置信息,包括构造函数参数,属性值和特定于容器的信息,例如初始化方法,静态工厂方法名称等。子 bean 定义可以从父 bean 定义继承配置数据。子 bean 的定义信息可以覆盖某些值,或者可以根据需要添加其他值。使用父 bean 和子 bean 的定义可以节省很多输入(实际上,这是一种模板的设计形式)。
文档已经解释的比较清楚了,bean 的定义就是包含了这个 bean 应该有的所有重要信息,并且它又提到了一个概念:bean 的定义信息也是有层次性的(联想 BeanFactory 的层次性),bean 的定义信息可以继承自某个已经有的定义信息,并覆盖父信息的一些配置值
javadoc解释
A BeanDefinition describes a bean instance, which has property values, constructor argument values, and further information supplied by concrete implementations. This is just a minimal interface: The main intention is to allow a BeanFactoryPostProcessor such as PropertyPlaceholderConfigurer to introspect and modify property values and other bean metadata.
BeanDefinition 描述了一个 bean 的实例,该实例具有属性值,构造函数参数值以及具体实现所提供的更多信息。 这只是一个最小的接口,它的主要目的是允许 BeanFactoryPostProcessor(例如 PropertyPlaceholderConfigurer )内省和修改属性值和其他 bean 的元数据。
对比起官方文档,javadoc 额外提了编码设计中 BeanDefinition 的使用:BeanFactoryPostProcessor 可以任意修改 BeanDefinition 中的信息。
BeanDefinition接口的方法定义
BeanDefinition 整体包含以下几个部分:
-
Bean 的类信息 - 全限定类名(beanClassName)
-
Bean 的属性 - 作用域(scope)、是否默认Bean(primary)、描述信息(description)等
-
Bean 与其他 Bean 的关系 - 父 Bean 名(parentName)、依赖的Bean(dependsOn)等
-
Bean 的行为特征 - 是否延迟加载(lazy)、是否自动注入(autowireCandidate)、初始化 / 销毁方法(initMethod / destroyMethod)等
-
Bean 的配置属性 - 构造器参数(constructionArgumentValues)、属性变量值(propertyValues)等
由此可见,BeanDefinition 几乎把 bean 的所有信息都能收集并封装起来,可以说是很全面了。
【面试题】面试中如何概述BeanDefinition
BeanDifinition 描述了SpringFramework 中 bean 的元信息,它包含 bean 的类信息、属性、行为、依赖关系、配置信息等。BeanDifinition 具有层次性,并且可以在 IOC 容器初始化阶段被 BeanDifinitionRegistryPostProcessor 构造和注册,被BeanFactoryPostProcessor 拦截修改等
BeanDefinition的结构
AbstractBeanDefinition
BeanDefinition 的第一个实现类了,作为 BeanDefinition 的抽象实现,它里面已经定义好了一些属性和功能
// bean的全限定类名
private volatile Object beanClass;
// 默认的作用域为单实例
private String scope = SCOPE_DEFAULT;
// 默认bean都不是抽象的
private boolean abstractFlag = false;
// 是否延迟初始化
private Boolean lazyInit;
// 自动注入模式(默认不自动注入)
private int autowireMode = AUTOWIRE_NO;
// 是否参与IOC容器的自动注入(设置为false则它不会注入到其他bean,但其他bean可以注入到它本身)
// 可以这样理解:设置为false后,你们不要来找我,但我可以去找你们
private boolean autowireCandidate = true;
// 同类型的首选bean
private boolean primary = false;
// bean的构造器参数和参数值列表
private ConstructorArgumentValues constructorArgumentValues;
// bean的属性和属性值集合
private MutablePropertyValues propertyValues;
// bean的初始化方法
private String initMethodName;
// bean的销毁方法
private String destroyMethodName;
// bean的资源来源
private Resource resource;
可以发现这些属性在BeanDifinition中基本都有了,在AbstractBeanDefinition抽象中在实现一次是针对不同的 BeanDefinition 落地实现,还有一些特殊的属性咯,所以还是需要抽象出一个父类才行哈。
GenericBeanDefinition
Generic代表着通用、一般的,所以这种 BeanDefinition 也具有一般性。GenericBeanDefinition 的源码实现非常简单,仅仅是比 AbstractBeanDefinition 多了一个 parentName 属性而已。
RootBeanDefinition与ChildBeanDefinition
root 和 child ,很明显这是父子关系的意思了呀。对于 ChildBeanDefinition ,它的设计实现与 GenericBeanDefinition 如出一辙,都是集成一个 parentName 来作为父 BeanDefinition 的 “指向引用” 。不过有一点要注意, ChildBeanDefinition 没有默认的无参构造器,必须要传入 parentName 才可以,但 GenericBeanDefinition 则有两种不同的构造器。
RootBeanDefinition 有着 “根” 的概念在里面,它只能作为单体独立的 BeanDefinition ,或者父 BeanDefinition 出现(不能继承其他 BeanDefinition )。
下面是 RootBeanDefinition 的一些重要的成员属性:
// BeanDefinition的引用持有,存放了Bean的别名
private BeanDefinitionHolder decoratedDefinition;
// Bean上面的注解信息
private AnnotatedElement qualifiedElement;
// Bean中的泛型
volatile ResolvableType targetType;
// BeanDefinition对应的真实的Bean
volatile Class<?> resolvedTargetType;
// 是否是FactoryBean
volatile Boolean isFactoryBean;
// 工厂Bean方法返回的类型
volatile ResolvableType factoryMethodReturnType;
// 工厂Bean对应的方法引用
volatile Method factoryMethodToIntrospect;
可以发现RootBeanDefinition又在AbstractBeanDefinition的基础上又扩展了下面这些 bean 的信息
-
Bean 的id和别名
-
Bean 的注解信息
-
Bean 的工厂相关信息(是否为工厂Bean、工厂类、工厂方法等)
而且这里面直接把一些反射相关的元素都包含进来了,可见 BeanDefinition 在底层可是要在反射上 “大动干戈”了。
AnnotatedBeanDefinition
这并不是BeanDefinition的实现类,而是一个子接口
public interface AnnotatedBeanDefinition extends BeanDefinition {
AnnotationMetadata getMetadata();
MethodMetadata getFactoryMethodMetadata();
}
BeanDifinition特征总结:
-
BeanDefinition 继承了 AttributeAccessor 接口,具有配置 bean 属性的功能。(配置 bean 就包含了访问、修改、移除在内的操作)
-
AbstractBeanDefinition 已经完全可以构成 BeanDefinition 的实现了
-
GenericBeanDefinition 就是 AbstractBeanDefinition 的非抽象扩展而已
-
GenericBeanDefinition 具有层次性(可从父 BeanDefinition 处继承一些属性信息)
体会BeanDefinition
基于xml和@Component构建BeanDefinition
使用 BeanDefinition personBeanDefinition = ctx.getBeanFactory().getBeanDefinition(beanName);
获取
xml和@Component 构建的 BeanDifinition 都是 Generic bean
xml:org.springframework.beans.factory.support.GenericBeanDefinition
@Component: org.springframework.context.annotation.ScannedGenericBeanDefinition
基于@Bean构建的BeanDifinition
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$ConfigurationClassBeanDefinition
- Bean 的类型是 Root bean ( ConfigurationClassBeanDefinition 继承自 RootBeanDefinition )
- Bean 的 className 不见了
- 自动注入模式为 AUTOWIRE_CONSTRUCTOR (构造器自动注入)
- 有 factoryBean 了:person 由 beanDefinitionQuickstartConfiguration 的 person 方法创建
BeanDefinition是如何生成的
-
通过xml加载的 BeanDifinition ,它的读取工具是
XMLBeanDifinitionReader
,它会解析 xml 配置文件,最终来到 DefaultBeanDifinitionDocumentReader 的 doRegisterBeanDefinition 方法,根据 xml 配置文件中的 bean 定义构造 BeanDifinition,最底层创建 BeanDifinition 的位置在 org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition 。 -
通过注解模式 + 组件扫描的方式构造的 BeanDifinition,它的扫描工具是
ClassPathBeanDifinitionScanner
,它会扫描指定路径下包含特定模式注解的类,核心工作的方法时 doScan() 方法,这个方法最终会调到父类ClassPathScanningCandidateComponentProvider
的 findCandidateComponent() 方法,创建ScannedGenericBeanDefinition
并返回 -
通过配置类 + @Bean 注解的方式构造的 BeanDifinition 最复杂,它涉及到配置类的解析。配置类的解析要追踪到
ConfigurationClassPostProcessor
的 ProcessConfigBeanDifinition() 方法,这个方法会处理配置类,并交给ConfigurationClassParser
类来解析配置类,取出所有标注了 @Bean 注解的方法。随后这些方法又被ConfigurationClassBeanDefinitionReader
类解析,最终在底层创建ConfigUrationClassBeanDefinition
并返回
思考
-
如何理解 BeanDefinition ?
BeanDifinition 是一种配置元信息,它描述了 Bean 的定义信息,包含 Bean 的类信息、属性、行为、依赖关系、配置信息等。
BeanDifinition 具有层次性。 -
BeanDefinition 中主要包含哪些信息?
Bean 的类信息 - 全限定名
Bean 的属性 - 作用域、是否为默认Bean、描述信息等
Bean 与其他 Bean 的关系 - 父 Bean 名,依赖 Bean 等
Bean 的行为特征 - 是否延迟加载、是否自动注入、初始化 / 销毁等
Bean 的配置属性 - 构造器参数、属性变量值 -
BeanDefinition 有哪些类型?分别都有什么特征?
GenericBeanDifinition:通用的BeanDifinition
ChildBeanDifinition:孩子BeanD
RootBeanDefinition:根BeanDifinition
AnnotationBeanDifinition:注解BeanDifinition