一、导读

BeanDefinitionSpring 框架中定义 Bean 的配置元信息接口,包含有:

  • Bean的类名
  • Bean行为配置元素,如 作用域自动绑定模式生命周期回调 (注解、方法)等
  • 其他Bean引用,可称为 合作者(Collaborators)依赖(Dependencies)
  • 配置设置,比如 Bean 属性(Properties) | 属性 | 说明 | | —- | —- | | Class | Bean全类名,必须是具体类,不能用抽象类或接口 | | Name | Bean的名称或ID | | Scope | Bean的作用域(singleton、prototype) | | Constructor arguments | Bean构造器参数(用于依赖注入) | | Properties | Bean属性设置(用于依赖注入) | | Autowiring Mode | Bean自动绑定模式(NO(default)、byType、byName) | | Lazy Initialization Mode | Bean延迟初始化模式(延迟、非延迟) | | Initialization Mothod | Bean初始化回调方法名称 | | Destruction Method | Bean销毁回调方法名称 |

对于 厨师 而言, BeanDefinition 就是一份菜谱,里面记录着一道菜从食材的选择到烹饪的火候等一系列操作,也像 曲谱 ,由乐者奏出美妙 音符 ♪。

二、从上帝视角看Spring的BeanDefinition体系结构

2.1 继承结构

BeanDefinition.png

2.2 剖析

1. AttributeAccessor

见名知义,属性获取接口。该接口定义了一个 通用的准则 获取任意实体的元数据。简单看一下该接口的方法:

  1. // AttributeAccessor
  2. public interface AttributeAccessor {
  3. void setAttribute(String name, @Nullable Object value);
  4. Object getAttribute(String name);
  5. Object removeAttribute(String name);
  6. boolean hasAttribute(String name);
  7. String[] attributeNames();
  8. }

2. BeanMetadataElement

// BeanMetadataElement
// 
public interface BeanMetadataElement {

    /**
     * Return the configuration source {@code Object} for this metadata element
     * (may be {@code null}).
     */
    @Nullable
    default Object getSource() {
        return null;
    }

}

由Bean元数据元素实现,该对象携带一个资源对象。如下图所示:
image.png
可以理解 .class 源文件。当然,如果被在配置类中被@Bean 注解标注的话,那么此时的 getSource 方法返回的是 StandardMethodMetadata 对象。表示该 Bean 是来源于某个配置方法。如下图所示:
beandefinition-source.png

3.BeanDefinition

BeanDefinition 描述了一个bean实例,该实例具有 属性值构造函数参数值 以及由具体实现类提供的更多信息。 这只是一个最小的接口:主要目的是允许 BeanFactoryPostProcessor 内省和 修改属性值 和其他Bean元数据信息。

说到 内省 ,我们看一下里面的 setter 方法:
beandefinition-setter-method.png
还有 isXX 方法:
beandefinition-is-method.png
是不是很熟悉,大致与我们常用的注解,如 @Lazy@Primary 等对应。解释几个少见的:

  • 生命周期回调方法
    • setInitMethodName
    • setDestroyMethodName
  • 父类信息
    • getParentName()
  • 获取构造函数参数
    • getConstructorArgumentValues()
  • 获取setter 方法参数
    • getPropertyValues()
  • 创建此类的类名
    • setFactoryBeanName(@Nullable String factoryBeanName)
  • 创建此类的方法名称
    • setFactoryMethodName(@Nullable String factoryMethodName);

当前 BeanDefinition 定义最基础的Bean信息,更丰富的信息,比如注解相关的,由子类完成。

4.AbstractBeanDefinition

抽象类,继承 BeanDefinition 接口,实现 BeanDefinition 绝大部分接口,但排除 GenericBeanDefinitionRootBeanDefinitionChildBeanDefinition 常用属性。里面定义了接口所需要的 数据结构 以及赋予默认值。方便子类扩展。

5.GenericBeanDefinition

Generic: 通用的。
它可以灵活设置 parentName 属性值,从 父bean 中继承属性值,甚至可以通过 后置处理器 重新配置父名称。在父/子关系恰好是预先确定的地方使用 RootBeanDefinition / ChildBeanDefinition

6.ScannedGenericBeanDefinition

/**
 * 基于ASM ClassReader的GenericBeanDefinition类的扩展,支持通过AnnotatedBeanDefinition接口获取注解元信息。
 *
 * 此类不会提早加载Bean类。
 * 而是从ASM ClassReader解析的“.class”文件本身以检索所有相关的元数据。
 * 它在功能上等效于AnnotatedGenericBeanDefinition.AnnotatedGenericBeanDefinition(AnnotationMetadata),
 * 但按类型区分已扫描的bean 和 已通过其他方式注册或检测到的bean。
 *
 */
@SuppressWarnings("serial")
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {

    private final AnnotationMetadata metadata;


    /**
     * 为给定的MetadataReader描述的类创建一个新的ScannedGenericBeanDefinition
     * @param metadataReader the MetadataReader for the scanned target class
     */
    public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
        Assert.notNull(metadataReader, "MetadataReader must not be null");
        this.metadata = metadataReader.getAnnotationMetadata();
        setBeanClassName(this.metadata.getClassName());
        setResource(metadataReader.getResource());
    }


    @Override
    public final AnnotationMetadata getMetadata() {
        return this.metadata;
    }

    @Override
    @Nullable
    public MethodMetadata getFactoryMethodMetadata() {
        return null;
    }
}

通过类扫描的都会变为此 ScannedGenericBeanDefinition
beandefinition-map.png

7.AnnotationGenericBeanDefinition

GenericBeanDefinition类的扩展,可以通过AnnotatedBeanDefinition接口暴露元注解信息。

//AnnotationGenericBeanDefinition
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
    setBeanClass(beanClass);
    // 内省当前BeanClass进行注解元数据
    this.metadata = AnnotationMetadata.introspect(beanClass);
}

Spring 内部中,使用 AnnotationConfigApplicationContext#register 或该类 构造方法 注册的 BeanDefinition 就是此类型。 注解@Import 导入的类也是此类型。

与ScannedGenericBeanDefinition区别

ScannedGenericBeanDefinition 是在将类路径扫描所得的类信息封装为此类型,采用的是 ASM 字节码技术,而 AnnotatedGenericBeanDefinition 使用标准反射API完成注解信息获取。

8.RootBeanDefinition

  • 根bean定义表示已合并的bean definition,该definition在运行时支持Spring BeanFactory中的特定bean。
  • 它可能是由多个相互继承的原始bean定义创建的,通常为GenericBeanDefinitions。
  • root bean definition本质上是运行时的“统一”bean定义视图。
  • 根Bean定义也可以在配置阶段用于注册各个Bean定义。
  • 但是,从Spring 2.5开始,以编程方式注册bean定义的首选方法是GenericBeanDefinition类。
  • GenericBeanDefinition的优点在于,它允许动态定义父项依赖项,而不是将角色“硬编码”为根bean定义

回顾Spring创建 RootBeanDefinition ,有以下几点:

  • AnnotationConfigApplicationContext 构造器中通过 AnnotationConfigUtils 注册6个重要的Spring内建对象,都是使用RootBeanDefinition 封装。
  • Spring在 DefaultListableBeanFactory#getMergedLocalBeanDefinition返回的对象为RootBeanDefinition。
  • @Bean解析生成的也是RootBeanDefinition(实际上是其子类ConfigurationClassBeanDefinition)

    9.ChildBeanDefinition

    Spring 2.5 开始,以编程的方式注册 BeanDefinition ,首选是 ChildBeanDefinition ,它可以动态定义父类依赖项。对大多数用例而言,使用 GenericBeanDefinition 取代 ChildBeanDefinition

    2.3 小结

    相信各位看到这里,对 SpringBeanDefiniton 有个大概的了解。不同层次、不同类型的 BeanDefinition 实现类表示拥有不同的能力。具有结构性的接口继承,便于维护和管理。在 Spring 内部使用 RootBeanDefinition 来做最后的菜谱,从里面获取配置信息实例化Bean对象。

    三、BeanDefinition合并操作

    若类存在继承关系,需要获取 merge beandefiniton 完成对 BeanDefinition 意义上的 继承 。显而意见

  • BeanDefinition 存在,子不存在,则子类继承其没有的属性值。

  • 若父、子存在相同属性,子不会被父类属性覆盖。

即没有的的拿过来,有的就不用管。