Spring容器创建过程源码学习-BeanDefinition 的注册(一)

BeanDefinition是在Spring 容器创建过程中用来描述Bean的一个对象,包含了Bean属性值、构造函数值以及一些其他定义的信息,

在容器创建之后,按照加载的BeanDefinition对象去创建相应的Bean。

1、BeanDefinition 描述的内容

从基础的 BeanDefinition 接口中提供的方法来看,一个BeanDefinition 有以下行为,大部分方法都是为了构建Bean的描述的,由此也能看出一个Bean应该具有哪些特征:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    // 设置父级BeanDefinition的名字,由此可知一个Bean定义对象支持关联一个父级的定义对象
    void setParentName(@Nullable String parentName);
    // 设置要定义Bean的类名
    void setBeanClassName(@Nullable String beanClassName);
    // 设置要定义Bean的作用域,即我们熟知的singleton、prototype等等
    void setScope(@Nullable String scope);
    // 设置要定义Bean是否延迟初始化(懒加载)
    void setLazyInit(boolean lazyInit);
    // 设置该Bean要依赖的其他Bean名称,这些Bean将优先初始化
    void setDependsOn(@Nullable String... dependsOn);
    // 设置该Bean是否自动装配到其他Bean中,仅影响按类型装配
    void setAutowireCandidate(boolean autowireCandidate);
    // 设置Bean初始化方法
    void setInitMethodName(@Nullable String initMethodName);
    // 设置Bean销毁方法
    void setDestroyMethodName(@Nullable String destroyMethodName);
}

以上方法均有一个对应的getter方法,用于获取配置的值。此外还包括Bean的属性值、构造函数参数值等定义信息。

此外该接口还继承了另外两个接口:

  • AttributeAccessor:提供设置和访问属性集合的能力,用于支持BeanDefinition 对象的元数据构建能力
  • BeanMetadataElement:Bean配置元数据数据源的储存对象接口,提供获取元数据对象的方法能力

2、BeanDefinition 的实现

Spring 中提供了一系列实现类来支持Bean定义对象的使用,通过不同的实现能够解析不同的Bean配置元数据,达到不同方式创建Bean的目的,例如传统xml配置文件形式、和注解形式。同时这些实现还支持在后置处理器中修改Bean的定义信息,提供更多扩展性能力。

Spring容器创建过程源码学习-BeanDefinition 的注册(一)_第1张图片

上图为整个BeanDefinition体系的继承和实现关系图,简单介绍一下上层接口的作用,再详细学习一下几个具体实现类的逻辑

  1. AbstractBeanDefinition:对BeanDefinition接口提供能力的一些基本公共实现和创建对象的基础处理,维护一些必须的成员变量。

  2. AttributeAccessorSupport:是对AttributeAccessor接口的支持,维护了存储属性集合的成员变量,实现了具体的设置和访问能力(使用Map存储具体元数据属性)。

  3. BeanMetadataAttributeAccessor:实现了BeanMetadataElement设置元数据数据源对象的能力,维护元数据的数据源对象;也对AttributeAccessorSupport进行了扩展,增加了专门用来设置元数据属性的方法,语义化更强,更符合单一职责。

    public void addMetadataAttribute(BeanMetadataAttribute attribute) {
        super.setAttribute(attribute.getName(), attribute);
    }
    
  4. AnnotatedBeanDefinition:是对BeanDefinition接口的扩展,提供了获取注解形式定义的Bean配置元数据的方法。

GenericBeanDefinition 标准的Bean定义对象

该类是注册Bean最常用的一个定义类,主要功能继承自AbstractBeanDefinition,并扩展对父定义的支持,兼容了RootBeanDefinitionChildBeanDefinition。先来看一下AbstractBeanDefinition中的成员变量,主要用来存储一个Bean定义所需的一些配置元数据:

// 存储Bean所属的类型,持有该Bean类对象的引用
private volatile Object beanClass;
// 存储Bean的作用域
private String scope = SCOPE_DEFAULT;
// 标识该Bean是否延迟加载
private Boolean lazyInit;
// 表示Bean的自动装配模式
private int autowireMode = AUTOWIRE_NO;
// 存储Bean依赖的其他Bean的名字
private String[] dependsOn;
// 存储Bean配置的构造函数参数值信息
private ConstructorArgumentValues constructorArgumentValues;
// 存储Bean配置的属性值信息
private MutablePropertyValues propertyValues;
// 存储Bean自定义初始化方法名称,将在Bean初始化的时候调用
private String initMethodName;
// 存储Bean自定义销毁方法名称,将在Bean销毁之前调用
private String destroyMethodName;
// 读取Bean定义配置的来源
private Resource resource;

GenericBeanDefinition单独维护一个成员变量支持子级对象的创建:

// 存储父级定义对象的名称
private String parentName;

GenericBeanDefinition包含两个构造器:

  • 无参构造器,创建一个空的Bean定义对象
  • 接收一个BeanDefinition类型参数构造器,按照另一个Bean定义对象创建一个新的对象(该对象的深拷贝)。此外还有一个方法也支持按照另一个对象的设置创建一个新的对象overrideFrom(BeanDefinition other),都是将参数对象的上述字段值设置到新对象里面。

下面列举一些主要方法,其他方法均是对成员变量的赋值和查询操作,感兴趣可查看源码:

// 用于设置Bean定义对象的默认值,接收一个默认值对象BeanDefinitionDefaults
void applyDefaults(BeanDefinitionDefaults defaults);
// 解析相关Bean的类,如果类没有加载,会先加载该类
Class<?> resolveBeanClass(@Nullable ClassLoader classLoader);
// 返回相关Bean的解析类型
ResolvableType getResolvableType();
// 返回Bean的属性注入方式,如果有无参构造,就用setter方法注入,否则是构造器注入
int getResolvedAutowireMode();

RootBeanDefinition父级Bean定义对象

该对象既可以当做一个普通的Bean定义对象,也可以当做子Bean定义对象的父级,子对象将继承父对象中的配置项。这里赋予了Bean定义的继承能力和合并能力,最大化的补全了Bean定义的属性。

随着越来越多注解声明Bean的使用,推荐使用GenericBeanDefinition处理通用的Bean定义对象。

ChildBeanDefinition子级Bean定义对象

该对象是作为上面父级对象的子级存在的,不能单独存在,用来表示具备继承配置的Bean定义存在,推荐使用GenericBeanDefinition。

注解方式声明Bean

AnnotatedBeanDefinition接口提供了获取声明Bean的注解的元数据的能力:

// 获取Bean定义的注解元数据
AnnotationMetadata getMetadata();
// 获取Bean定义的工厂方法的元数据
MethodMetadata getFactoryMethodMetadata();

AnnotatedGenericBeanDefinition是AnnotatedBeanDefinition接口的主要实现类,并且继承了GenericBeanDefinition的所有能力。维护了存储注解元数据metadata和工厂方法原数据的变量factoryMethodMetadata,并实现了接口的方法。主要的两个构造器如下:

//接收Bean的类对象参数
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
    // 设置Bean的类型,在上文AbstractBeanDefinition中定义
    setBeanClass(beanClass);
    // 设置该给的注解原数据,通过Class对象反射获得类上的注解信息
    this.metadata = AnnotationMetadata.introspect(beanClass);
}

// 接收注解元数据参数
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
    Assert.notNull(metadata, "AnnotationMetadata must not be null");
    // 通过注解元数据对象解析出对应Bean的类型
    if (metadata instanceof StandardAnnotationMetadata) {
        setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
    }
    else {
        setBeanClassName(metadata.getClassName());
    }
    // 设置元数据对象
    this.metadata = metadata;
}

ScannedGenericBeanDefinition 主要用于用于创建包扫描出的Bean定义对象,支持通过类的元数据进行创建对象。后续将在使用中再次介绍这个类型。

// 存储该定义对象的注解
private final AnnotationMetadata metadata;

public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
    Assert.notNull(metadataReader, "MetadataReader must not be null");
    // 获取参数中提供的注解元数据对象
    this.metadata = metadataReader.getAnnotationMetadata();
    // 获取参数中提供的类名称
    setBeanClassName(this.metadata.getClassName());
}
// 该接口类型支持对类文件元数据的访问
public interface MetadataReader {
    // 对源文件资源的访问
    Resource getResource();
    // 对类文件类的元数据访问
    ClassMetadata getClassMetadata();
    // 对类文件的类的注解元数据访问
    AnnotationMetadata getAnnotationMetadata();
}

ConfigurationClassBeanDefinition是ConfigurationClassBeanDefinitionReader中的一个内部类,ConfigurationClassBeanDefinitionReader是加载由用户自定义的@Configuration标注的类中Bean,因此ConfigurationClassBeanDefinition就是为此类Bean创建定义对象的。不再展示该类代码,在后面解析Spring注册BeanDefinition代码中会介绍如何使用。

3、总结

BeanDefinition是一个对Spring中的Bean的定义对象,描述了创建一个标准Bean所需的众多属性。Spring内置了六种实现类来支持多中Bean定义形式:xml格式配置、注解配置、包自动扫描和@Configuration四种形式。加载并注册BeanDefinition是Spring工厂创建的一个重要步骤,后续的Bean创建会依赖BeanDefinition的定义去严格创建。

本文只了解一下BeanDefinition的定义和大家族中各个类的使用形式以及主要实现逻辑,下一篇文章将介绍Sping是如何为Bean注册这些定义对象的。

原文地址

你可能感兴趣的:(spring)