前面我们讲了元信息的相关概念,今天要讲的 BeanDefinition 就是一种配置元信息,用来描述了 Bean 的定义信息。

1. 概念

1.1 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 描述了 SpringFramework 中 bean 的元信息,它包含 bean 的类信息、属性、行为、依赖关系、配置信息等。而且 BeanDefinition 具有层次性,可以在 IOC 容器初始化阶段被 BeanDefinitionRegistryPostProcessor 构造和注册,被 BeanFactoryPostProcessor 拦截修改等。

至于 BeanDefinitionRegistryPostProcessor 和 BeanFactoryPostProcessor 我们后面会学习。

1.2 方法列表

通过 IDEA 打开它的 Structure ,然后看下方法列表,一堆 get set,其实就能知道一个 BeanDefiniton 中含有哪些内容。

  • Bean 的类信息:
    • 全限定类名 ( beanClassName )
  • Bean 的属性:
    • 作用域 ( scope )
    • 是否默认 Bean ( primary )
    • 描述信息 ( description ) 等
  • Bean 的行为特征:
    • 是否延迟加载 ( lazy )
    • 是否自动注入 ( autowireCandidate )
    • 初始化 / 销毁方法 ( initMethod / destroyMethod ) 等
  • Bean 与其他 Bean 的关系:
    • 父 Bean 名 ( parentName )
    • 依赖的 Bean ( dependsOn ) 等
  • Bean 的配置属性:
    • 构造器参数 ( constructorArgumentValues )
    • 属性变量值 ( propertyValues ) 等

      2. 结构

      继承图我只截取了一部分哈,下面的实现类还有几个。
      image.png

2.1 AttributeAccessor

Interface defining a generic contract for attaching and accessing metadata to/from arbitrary objects.

接口,定义了用于向任意对象附加和访问元数据的通用契约。

先来看最定级的接口,可以看到它的描述就是一个熟悉的访问器,再看它的方法,其实能看出来,它提供了一种 get set remove 的能力,所以 BeanDefinition 继承了 AttributeAccessor 接口,它也就有了配置修改 bean 属性的能力。

  1. public interface AttributeAccessor {
  2. // 设置bean中属性的值
  3. void setAttribute(String name, @Nullable Object value);
  4. // 获取bean中指定属性的值
  5. Object getAttribute(String name);
  6. // 移除bean中的属性
  7. Object removeAttribute(String name);
  8. // 判断bean中是否存在指定的属性
  9. boolean hasAttribute(String name);
  10. // 获取bean的所有属性
  11. String[] attributeNames();
  12. }

2.2 BeanMetadataElement

这个标题名就很元数据的样子,它的用途是存放了 bean 的元信息。接口只有一个方法,即获取 bean 的资源来源

  1. public interface BeanMetadataElement {
  2. default Object getSource() {
  3. return null;
  4. }
  5. }

资源来源,就是 bean 的文件 / url 路径。本地磁盘上的 .class 文件加载后,对应会用 FileSystemResource 加载。

2.3 AbstractBeanDefinition

AbstractBeanDefinition 作为 BeanDefinition 的抽象实现,它里面已经定义好了一些属性和功能(大部分),下面节选显示一些

  1. // bean的全限定类名
  2. private volatile Object beanClass;
  3. // 默认的作用域为单实例
  4. private String scope = SCOPE_DEFAULT;
  5. // 默认bean都不是抽象的
  6. private boolean abstractFlag = false;
  7. // 是否延迟初始化
  8. private Boolean lazyInit;
  9. // 自动注入模式(默认不自动注入)
  10. private int autowireMode = AUTOWIRE_NO;
  11. // 是否参与IOC容器的自动注入(设置为false则它不会注入到其他bean,但其他bean可以注入到它本身)
  12. // 可以这样理解:设置为false后,你们不要来找我,但我可以去找你们
  13. private boolean autowireCandidate = true;
  14. // 同类型的首选bean
  15. private boolean primary = false;
  16. // bean的构造器参数和参数值列表
  17. private ConstructorArgumentValues constructorArgumentValues;
  18. // bean的属性和属性值集合
  19. private MutablePropertyValues propertyValues;
  20. // bean的初始化方法
  21. private String initMethodName;
  22. // bean的销毁方法
  23. private String destroyMethodName;
  24. // bean的资源来源
  25. private Resource resource;

为什么要抽象呢?

Base class for concrete, full-fledged BeanDefinition classes, factoring out common properties of GenericBeanDefinition, RootBeanDefinition, and ChildBeanDefinition. The autowire constants match the ones defined in the AutowireCapableBeanFactory interface.

它是 BeanDefinition 接口的抽象实现类,其中排除了 GenericBeanDefinitionRootBeanDefinitionChildBeanDefinition 的常用属性。 自动装配常量与 AutowireCapableBeanFactory 接口中定义的常量匹配。

原因就是对于不同的 BeanDefinition 实现,还有一些特殊的属性,所以还是需要抽象出一个父类才行哈。

2.4 GenericBeanDefinition

Generic 前缀代表通用、一般的,GenericBeanDefinition 的源码仅仅是比 AbstractBeanDefinition 多了一个 parentName 属性。
所以 AbstractBeanDefinition 已经完全可以构成 BeanDefinition 的实现了,GenericBeanDefinition 只是多了一层扩展。

2.5 RootBeanDefinition与ChildBeanDefinition

这两个实现也是通过 parentName 来作为父 BeanDefinition 的 “指向引用”,不过 child 没有默认的无参构造,一定要传入 parentName。
它的扩展就非常多,其中标注几个常见的,其中能看到已经存入了反射相关的内容了,所以说明它对于反射有了扩展。

// 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;

3. 测试

使用 xml 配置文件的方式,每定义一个 标签,就相当于构建了一个 BeanDefinition,注解也是一样。
基于 xml 解析出来的 bean ,定义来自 xml 配置文件,基于 @Component 注解解析出来的 bean ,定义来自类的 .class 文件。

public class BeanDefinitionXmlTest {

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("definition-beans.xml");
        BeanDefinition personBeanDefinition = ctx.getBeanFactory().getBeanDefinition("person");
        System.out.println(personBeanDefinition);
    }
}
public class BeanDefinitionComponentTest {

    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
                "com.ideal.bean");
        BeanDefinition personBeanDefinition = ctx.getBeanDefinition("person");
        System.out.println(personBeanDefinition);
        System.out.println(personBeanDefinition.getClass().getName());
    }
}

4. BeanDefinitionRegistry

为什么提它呢,因为我们的 BeanDefinition 需要配合 BeanDefinitionRegistry 才能实现注册。

Interface for registries that hold bean definitions, for example RootBeanDefinition and ChildBeanDefinition instances. Typically implemented by BeanFactories that internally work with the AbstractBeanDefinition hierarchy. This is the only interface in Spring’s bean factory packages that encapsulates registration of bean definitions. The standard BeanFactory interfaces only cover access to a fully configured factory instance. Spring’s bean definition readers expect to work on an implementation of this interface. Known implementors within the Spring core are DefaultListableBeanFactory and GenericApplicationContext.

用于保存bean定义的注册中心的接口,例如RootBeanDefinition和ChildBeanDefinition实例。通常由内部使用AbstractBeanDefinition层次结构的beanfactory实现。这是Spring bean工厂包中封装bean定义注册的唯一接口。标准的BeanFactory接口只包括对完全配置的工厂实例的访问。Spring bean定义的读者希望处理这个接口的实现。Spring核心中已知的实现者是DefaultListableBeanFactory和GenericApplicationContext。

4.1 概述

4.1.1 存放了所有BeanDefinition

// 源自DefaultListableBeanFactory
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

4.1.2 维护了BeanDefinition

增删查

void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;

void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

4.1.3 支撑其它组件运行

XmlBeanDefinitionReader ,它是用来读取和加载 xml 配置文件的组件。加载 xml 配置文件的目的就是读取里面的配置,和定义好要注册到 IOC 容器的 bean 。XmlBeanDefinitionReader 要在加载完 xml 配置文件后,将配置文件的流对象也好,文档对象也好,交给解析器来解析 xml 文件,解析器拿到 xml 文件后要解析其中定义的 bean ,并且封装为 BeanDefinition 注册到 IOC 容器,这个时候就需要 BeanDefinitionRegistry 了。所以在这个过程中,BeanDefinitionRegistry 会支撑 XmlBeanDefinitionReader 完成它的工作。—— 《从 0 开始深入学习 Spring》

4.1.4 主要实现是DefaultListableBeanFactorya

落地实现有 DefaultListableBeanFactory 和 SimpleBeanDefinitionRegistry ,但是主要是前者。

4.2 怎么理解?

BeanDefinitionRegistry 是维护 BeanDefinition 的注册中心,它内部存放了 IOC 容器中 bean 的定义信息,同时 BeanDefinitionRegistry 也是支撑其它组件和动态注册 Bean 的重要组件。在 SpringFramework 中,BeanDefinitionRegistry 的实现是 DefaultListableBeanFactory 。