SpringFramework — BeanDifinition

小龙 294 2022-05-17

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的结构

image-1652777671502

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是如何生成的

  1. 通过xml加载的 BeanDifinition ,它的读取工具是 XMLBeanDifinitionReader,它会解析 xml 配置文件,最终来到 DefaultBeanDifinitionDocumentReader 的 doRegisterBeanDefinition 方法,根据 xml 配置文件中的 bean 定义构造 BeanDifinition,最底层创建 BeanDifinition 的位置在 org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition 。

  2. 通过注解模式 + 组件扫描的方式构造的 BeanDifinition,它的扫描工具是 ClassPathBeanDifinitionScanner,它会扫描指定路径下包含特定模式注解的类,核心工作的方法时 doScan() 方法,这个方法最终会调到父类 ClassPathScanningCandidateComponentProviderfindCandidateComponent() 方法,创建 ScannedGenericBeanDefinition 并返回

  3. 通过配置类 + @Bean 注解的方式构造的 BeanDifinition 最复杂,它涉及到配置类的解析。配置类的解析要追踪到 ConfigurationClassPostProcessorProcessConfigBeanDifinition() 方法,这个方法会处理配置类,并交给 ConfigurationClassParser 类来解析配置类,取出所有标注了 @Bean 注解的方法。随后这些方法又被 ConfigurationClassBeanDefinitionReader 类解析,最终在底层创建 ConfigUrationClassBeanDefinition 并返回

思考

  1. 如何理解 BeanDefinition ?

    BeanDifinition 是一种配置元信息,它描述了 Bean 的定义信息,包含 Bean 的类信息、属性、行为、依赖关系、配置信息等。
    BeanDifinition 具有层次性。

  2. BeanDefinition 中主要包含哪些信息?

    Bean 的类信息 - 全限定名
    Bean 的属性 - 作用域、是否为默认Bean、描述信息等
    Bean 与其他 Bean 的关系 - 父 Bean 名,依赖 Bean 等
    Bean 的行为特征 - 是否延迟加载、是否自动注入、初始化 / 销毁等
    Bean 的配置属性 - 构造器参数、属性变量值

  3. BeanDefinition 有哪些类型?分别都有什么特征?

    GenericBeanDifinition:通用的BeanDifinition
    ChildBeanDifinition:孩子BeanD
    RootBeanDefinition:根BeanDifinition
    AnnotationBeanDifinition:注解BeanDifinition


# IOC