Spring源码(3)-BeanDefinition


一、简介

Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。

不管是是通过xml配置文件的 <Bean> 标签,还是通过注解配置的 @Bean,它最终都会被解析成一个Bean定义信息(对象),最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。

BeanDefinition 作用是将不管任何形式定义的 Bean 转化为一个统一的格式,方便工厂后续的处理。

下面用一个非常形象的比喻,来形容Spring IoC容器和BeanDefinition之前的关系。

比喻:BeanFactory和BeanDefinition

Spring IoC容器比作一间餐馆,当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。

IoC容器也是一样,你只需要告诉它需要某个bean,它就把对应的实例(instance)扔给你,至于这个bean是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。

那么问题来了,作为餐馆,想要做出菜肴,得知道菜的原料和菜谱。同样地,IoC容器想要管理各个业务对象以及它们之间的依赖关系,需要通过某种途径来记录和管理这些信息。 BeanDefinition对象就承担了这个责任。

容器中的每一个bean都会有一个对应的BeanDefinition实例,该实例负责保存bean对象的 所有 必要信息,包括bean对象的class类型、是否是抽象类、构造方法和参数、其它属性等等

  • 包限定的类名:通常,定义了 Bean 的实际实现类。
  • Bean 行为配置元素,用于声明 Bean 在容器中的行为(作用域,生命周期回调等)。
  • 引用其他 bean 进行其工作所需的 bean。这些引用也称为协作者或依赖项。
  • 要在新创建的对象中设置的其他配置设置,例如,池的大小限制或在 Management 连接池的 bean 中使用的连接数。

简而言之,BeanDefinition就是用来描述 Spring 应该如何创建指定的 Bean

BeanDefinitionRegistryBeanFactory 就是这份菜谱,BeanDefinitionRegistry 抽象出bean的注册逻辑,而 BeanFactory 则抽象出了bean的管理逻辑,各个 BeanFactory 的实现类就具体承担了bean的注册以及管理工作。

DefaultListableBeanFactory 作为一个比较通用的 BeanFactory 实现,它同时也实现了BeanDefinitionRegistry 接口,因此它就承担了Bean的注册管理工作。

BeanDefinition 是容器对于bean配置的内部表示,Spring 将各个 beanBeanDefinition 实例注册记录在 BeanDefinitionRegistry 中,该接口定义了对 BeanDefinition 的各种增删查操作,类似于内存数据库,其实现类 SimpleBeanDefinitionRegistry 主要以 Map 作为存储标的。

注:本篇文章使用的 SpringBoot 版本为 2.0.3.RELEASE,其 Spring 版本为 5.0.7.RELEASE

spring中的bean,在Java类的基础上增加了很多概念属性,比如scope(作用域),isLazyInit(是否延迟初始化),isSingleton(是否单例)等属性特征。spring就是根据BeanDefinition来实例化对应的bean。

处理BeanDefinition分为三个阶段:BeanDefinition的解析,注册,合并。

二、BeanDefinition继承体系

现如今,我们一般获取对象的方式有两种,一种是手动直接 new;另一种是交给 Spring 管理,Spring 将管理的对象称之为 Bean,容器会先实例化 Bean,然后自动注入,实例化的过程就需要依赖 BeanDefinition

BeanDefinition 用于保存 Bean 的相关信息,包括属性、构造方法参数、依赖的 Bean 名称及是否单例、延迟加载等,它是实例化 Bean 的原材料,Spring 就是根据 BeanDefinition 中的信息实例化 Bean。

1、父类

BeanDefinition 继承了 AttributeAccessorBeanMetadataElement

(1)AttributeAccessor

定义了对对象元数据访问的抽象接口

注意:设置的是 BeanDefinition 的属性值,而不是设置生成的 bean 的属性值

public interface AttributeAccessor {

    /**
     * 为指定的属性设置值
     */
    void setAttribute(String name, @Nullable Object value);

    /**
     * 获取指定属性的值
     */
    @Nullable
    Object getAttribute(String name);

    /**
     * 返回指定属性值,并移除该属性
     */
    @Nullable
    Object removeAttribute(String name);

    /**
     * 判断是否包含指定属性
     */
    boolean hasAttribute(String name);

    /**
     * 返回所有的属性名
     */
    String[] attributeNames();

}     

AttributeAccessorSupportAttributeAccessor 唯一抽象实现,内部基于 LinkedHashMap实现了所有的接口,供其他子类继承使用 主要针对属性CRUD操作。

(2)BeanMetadataElement

具有访问source(配置源)的能力,这个方法在 @Configuration 中使用较多,因为它会被代理。

public interface BeanMetadataElement {

    /**
     * 返回元数据配置元
     */
    @Nullable
    default Object getSource() {
        return null;
    }

}

(3)实例代码

public static void main(String[] args) throws InterruptedException {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

    GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClassName("com.suger.Rabbit");
    //设置属性值
    beanDefinition.setAttribute("name","tantan");
    //将beanDefinition注册到spring容器中
    context.registerBeanDefinition("rabbit",beanDefinition);

    //加载或者刷新当前的配置信息,新加的BeanDifinition必须要在容器刷新之后才会创建bean
    context.refresh();

    //拿到所有的属性名
    String[] attributes = context.getBeanDefinition("rabbit").attributeNames();
    System.out.println(Arrays.toString(attributes));//[name]

    //获取指定的属性值
    String nameAttr = (String)context.getBeanDefinition("rabbit").getAttribute("name");
    System.out.println(nameAttr);//tantan

    // 获取配置源
    Object soutce = context.getBeanDefinition("rabbit").getSource();
    System.out.println(soutce);//null

    //获取beanDefinition定义的bean对象
    Rabbit rabbit = (Rabbit)context.getBean("rabbit");
    //after refresh:Rabbit{name='null'}
    System.out.println("after refresh:" + rabbit);

}

2、子类

BeanDefinition 是一个接口,它有多个实现类,这些实现类分别描述不同类型的 Bean。

image-20220924210227458

  • AnnotatedBeanDefinition:用于描述通过注解获得的 Bean
  • AbstractBeanDefinition:具体的、功能完备的 BeanDefinition 类的基类,实现了大部分方法,实现了 是下面三个的父类:
    • RootBeanDefinition:最顶层父BeanDefinition,不可有parent BeanDefinition
    • ChildBeanDefinition:子 BeanDefinition,必须依赖一个RootBeanDefinition
    • GenericBeanDefinition :Spring 2.5之后引入,即可作为父BeanDefinition,又可作为子 BeanDefinition,编码时一般使用这个即可

三、BeanDefinition

一个 BeanDefinition 描述了一个 Bean 实例,实例包含属性值、构造方法参数值以及更多实现信息。该 BeanDefinition 只是是一个最小的接口,主要目的是允许修改属性值和其他 Bean 元数据,这里列出几个核心方法。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    // 单例Bean还是原型Bean(singleton/prototype)
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

    // Bean角色:用户定义的 Bean、来源于配置文件的 Bean、Spring 内部的 Bean
    //指示BeanDefinition是应用程序的主要部分,通常对应于用户定义的bean。
    int ROLE_APPLICATION = 0;
    //指示BeanDefinition是一些较大配置的支持部分,通常是一个输出
    int ROLE_SUPPORT = 1;
    //表明BeanDefinition提供的是一个完全的后台角色,与最终用户无关。当注册完全属于ComponentDefinition内部工作的一部分的bean时,使用此提示。
    int ROLE_INFRASTRUCTURE = 2;

    // 设置、返回 Bean 的父类名称
    void setParentName(@Nullable String parentName);
    String getParentName();

    // 设置、返回 Bean 的 className
    void setBeanClassName(@Nullable String beanClassName);
    String getBeanClassName();

    // 设置、返回 Bean 的作用域
    void setScope(@Nullable String scope);
    String getScope();

    // 设置、返回 Bean 是否懒加载
    void setLazyInit(boolean lazyInit);
    boolean isLazyInit();

    // 设置、返回当前 Bean 所依赖的其它 Bean 名称。
    void setDependsOn(@Nullable String... dependsOn);
    String[] getDependsOn();

    // 设置、返回 Bean 是否可以自动注入。只对 @Autowired 注解有效
    void setAutowireCandidate(boolean autowireCandidate);
    boolean isAutowireCandidate();

    // 设置、返回当前 Bean 是否为主要候选 Bean 。
    // 当同一个接口有多个实现类时,通过该属性来配置某个 Bean 为主候选 Bean。
    void setPrimary(boolean primary);
    boolean isPrimary();

    // 设置、返回创建该 Bean 的工厂类。
    void setFactoryBeanName(@Nullable String factoryBeanName);
    String getFactoryBeanName();

    // 设置、返回创建该 Bean 的工厂方法
    void setFactoryMethodName(@Nullable String factoryMethodName);
    String getFactoryMethodName();

    // 返回该 Bean 构造方法参数值、所有属性
    ConstructorArgumentValues getConstructorArgumentValues();
    MutablePropertyValues getPropertyValues();

    // 返回该 Bean 是否是单例、是否是非单例、是否是抽象的
    boolean isSingleton();
    boolean isPrototype();
    boolean isAbstract();

    // 返回 Bean 的类别。类别对应上面的三个属性值。
    int getRole();

    ...
}

可以看到 BeanDefinition 接口提供了一系列操作 Bean 元数据的set、get方法,这些操作为 Bean 的描述定义了一套模板,具体的实现则交由子类。

1、AnnotatedBeanDefinition

AnnotatedBeanDefinitionBeanDefinition 子接口之一,该接口扩展了 BeanDefinition 的功能,其用来操作注解元数据。一般情况下,通过注解方式得到的 Bean(@Component@Bean),其 BeanDefinition 类型都是该接口的实现类。

public interface AnnotatedBeanDefinition extends BeanDefinition {

    // 获得当前 Bean 的注解元数据
    AnnotationMetadata getMetadata();

    // 获得当前 Bean 的工厂方法上的元数据
    MethodMetadata getFactoryMethodMetadata();
}

该接口可以返回两个元数据的类:

  • AnnotationMetadata:主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。
  • MethodMetadata:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。

2、AbstractBeanDefinition

具体的、功能完备的 BeanDefinition 类的基类,分解出 GenericBeanDefinitionRootBeanDefinitionChildBeanDefinition 的公共属性

AbstractBeanDefinitionBeanDefinition 的子抽象类,也是其他 BeanDefinition 类型的基类,其实现了接口中定义的一系列操作方法,并定义了一系列的常量属性,这些常量会直接影响到 Spring 实例化 Bean 时的策略。核心属性如下。

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
        implements BeanDefinition, Cloneable {

    // 默认的 SCOPE,默认是单例
    public static final String SCOPE_DEFAULT = "";


    /* ---------------- 定义自动装配方式 -------------------*/
    // 不进行自动装配
    public static final int AUTOWIRE_NO = 
        AutowireCapableBeanFactory.AUTOWIRE_NO;
    // 根据 Bean 的名字进行自动装配,byName
    public static final int AUTOWIRE_BY_NAME = 
        AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
    // 根据 Bean 的类型进行自动装配,byType
    public static final int AUTOWIRE_BY_TYPE = 
        AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
    // 根据构造器进行自动装配
    public static final int AUTOWIRE_CONSTRUCTOR = 
        AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
    // 首先尝试按构造器自动装配。如果失败,再尝试使用 byType 进行自动装配。(Spring 3.0 之后已废除)
    public static final int AUTOWIRE_AUTODETECT = 
        AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;


    /*---通过依赖检查来查看 Bean 的每个属性是否都设置完成,默认不进行依赖检查---*/
    //不检查
    public static final int DEPENDENCY_CHECK_NONE = 0;
    //如果依赖类型为对象引用,则需要检查
    public static final int DEPENDENCY_CHECK_OBJECTS = 1;
    //对简单属性(基本类型,字符串和集合)的依赖进行检查
    public static final int DEPENDENCY_CHECK_SIMPLE = 2;
    //对全部属性进行检查
    public static final int DEPENDENCY_CHECK_ALL = 3;


    // 关闭应用上下文时需调用的方法名称
    //若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字,目前来说,推断的销毁方法的名字一般为close或是shutdown
    //(即未指定Bean的销毁方法,但是内部定义了名为close或是shutdown的方法,则容器推断其为销毁方法)
    public static final String INFER_METHOD = "(inferred)";


    /*---------属性:基本囊括了Bean实例化需要的所有信息---------------*/
    // 存放 Bean 的 Class 对象
    private volatile Object beanClass;

    // Bean 的作用范围
    private String scope = SCOPE_DEFAULT;

    // 非抽象
    private boolean abstractFlag = false;
    // 非延迟加载
    private boolean lazyInit = false;
    // 默认不自动装配
    private int autowireMode = AUTOWIRE_NO;
    // 默认不依赖检查
    private int dependencyCheck = DEPENDENCY_CHECK_NONE;

    // 依赖的 Bean 列表
    private String[] dependsOn;

    // 可以作为自动装配的候选者,意味着可以自动装配到其他 Bean 的某个属性中
    private boolean autowireCandidate = true;

    // 默认不是首选的
    private boolean primary = false;



    // 创建当前 Bean 实例工厂类名称
    private String factoryBeanName;
    // 创建当前 Bean 实例工厂类中方法名称
    private String factoryMethodName;

    // 存储构造方法的参数
    private ConstructorArgumentValues constructorArgumentValues;
    // 存储 Bean 属性名称以及对应的值
    private MutablePropertyValues propertyValues;
    // 存储被覆盖的方法信息
    private MethodOverrides methodOverrides;

    // init、destroy 方法名称
    private String initMethodName;
    private String destroyMethodName;

    // 是否执行 init 和 destroy 方法
    private boolean enforceInitMethod = true;
    private boolean enforceDestroyMethod = true;

    // Bean 是否是用户定义的而不是应用程序本身定义的
    private boolean synthetic = false;

    // Bean 的身份类别,默认是用户定义的 Bean
    private int role = BeanDefinition.ROLE_APPLICATION;

    // Bean 的描述信息
    private String description;

    // Bean 定义的资源
    private Resource resource;

    ...
}

以上是 AbstractBeanDefinition 中定义的一些常量和属性,该类中还有一部分是操作这些属性的 set 和 get 方法,这些方法都由子类来操作,且应用程序中真正使用的也是这些子类 BeanDefinition。

先来看 AbstractBeanDefinition 直接实现类:RootBeanDefinitionGenericBeanDefinitionChildBeanDefinition

(1)RootBeanDefinition

该类继承自 AbstractBeanDefinition,他表示一个顶层的 BeanDefinition,无法对其调用 setParentName 设置其 parent, 它可以单独作为一个 BeanDefinition,也可以作为其他 BeanDefinition 的父类。

一个RootBeanDefinition 定义表明它是一个可合并的 bean definition:即在spring beanFactory 运行期间,可以返回一个特定的bean。但在Spring2.5以后,我们绝大多数情况还是可以使用 GenericBeanDefinition来做。

子类Bean定义它所引用它的父类Bean。这时前面的class属性失效。子类Bean会继承父类Bean的所有属性,子类Bean也可以覆盖父类Bean的属性

我们非常熟悉的

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

这句代码,就是去合并parent的属性进来,这样体现了继承的强大。属性也才完整。

RootBeanDefinitionAbstractBeanDefinition 的基础上定义了更多属性。

public class RootBeanDefinition extends AbstractBeanDefinition {

    // BeanDefinitionHolder 存储 Bean 的名称、别名、BeanDefinition
    private BeanDefinitionHolder decoratedDefinition;

    // AnnotatedElement 是java反射包的接口,通过它可以查看 Bean 的注解信息
    private AnnotatedElement qualifiedElement;

    // 允许缓存
    boolean allowCaching = true;

    // 工厂方法是否唯一
    boolean isFactoryMethodUnique = false;

    // 封装了 java.lang.reflect.Type,提供了泛型相关的操作
    volatile ResolvableType targetType;

    // 缓存 Class,表示 RootBeanDefinition 存储哪个类的信息
    volatile Class<?> resolvedTargetType;

    // 缓存工厂方法的返回类型
    volatile ResolvableType factoryMethodReturnType;

    // 这是以下四个构造方法字段的通用锁
    final Object constructorArgumentLock = new Object();
    // 用于缓存已解析的构造方法或工厂方法
    Executable resolvedConstructorOrFactoryMethod;
    // 将构造方法参数标记为已解析
    boolean constructorArgumentsResolved = false;
    // 用于缓存完全解析的构造方法参数
    Object[] resolvedConstructorArguments;
    // 缓存待解析的构造方法参数
    Object[] preparedConstructorArguments;

    // 这是以下两个后处理字段的通用锁
    final Object postProcessingLock = new Object();
    // 表明是否被 MergedBeanDefinitionPostProcessor 处理过
    boolean postProcessed = false;
    // 在生成代理的时候会使用,表明是否已经生成代理
    volatile Boolean beforeInstantiationResolved;

    // 实际缓存的类型是 Constructor、Field、Method 类型
    private Set<Member> externallyManagedConfigMembers;

    // InitializingBean中 的 init 回调函数名 afterPropertiesSet 会在这里记录,以便进行生命周期回调
    private Set<String> externallyManagedInitMethods;

    // DisposableBean 的 destroy 回调函数名 destroy 会在这里记录,以便进生命周期回调
    private Set<String> externallyManagedDestroyMethods;

    ...
}

(2)ChildBeanDefinition

该类继承自 AbstractBeanDefinition。其相当于一个子类,不可以单独存在,必须依赖一个 RootBeanDetintion,构造 ChildBeanDefinition 时,通过构造方法传入父 BeanDetintion 的名称或通过 setParentName 设置父名称。它可以从父类继承方法参数、属性值,并可以重写父类的方法,同时也可以增加新的属性或者方法。若重新定义 init 方法,destroy 方法或者静态工厂方法,ChildBeanDefinition 会重写父类的设置。

从 Spring 2.5 开始,以编程方式注册 Bean 定义的首选方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的绝大分部使用场合。

(3)GenericBeanDefinition

标准bean definition,通用的

GenericBeanDefinition 是 Spring 2.5 以后新引入的 BeanDefinition,是 ChildBeanDefinition更好的替代者,它同样可以通过 setParentName 方法设置父 BeanDefinition

除了具有指定类、可选的构造参数值和属性参数这些其它bean definition一样的特性外,它还具有通过parenetName属性来灵活(动态)设置parent bean definition,而非硬编码作为rootBeanDefinition

备注:若你是xml配置,最初被加载进来都是一个GenericBeanDefinition,之后再逐渐解析的。

public class GenericBeanDefinition extends AbstractBeanDefinition {

    @Nullable
    private String parentName;

    @Override
    public void setParentName(@Nullable String parentName) {
        this.parentName = parentName;
    }

    @Override
    @Nullable
    public String getParentName() {
        return this.parentName;
    }
}

使用案例代码

public static void main(String[] args) {
    AnnotationConfigApplicationContext applicationContext = 
        new AnnotationConfigApplicationContext(RootConfig.class);

    // 向工厂里注册Bean信息
    GenericBeanDefinition parentBeanDef = new GenericBeanDefinition();
    parentBeanDef.setBeanClass(Parent.class);
    parentBeanDef.setBeanClassName(Parent.class.getName());
    parentBeanDef.setScope(BeanDefinition.SCOPE_SINGLETON);

    // 就这样,我们可以动态的给子Bean 设置一个父Bean进去
    GenericBeanDefinition childBeanDef = new GenericBeanDefinition();
    childBeanDef.setParentName(parentBeanDef.getBeanClassName());
    childBeanDef.setBeanClass(Child.class);

    applicationContext.registerBeanDefinition("parent", parentBeanDef);
    applicationContext.registerBeanDefinition("child", childBeanDef);

    System.out.println(applicationContext.getBeanDefinition("parent"));
    System.out.println(applicationContext.getBeanDefinition("child")); 
}

(4)BeanDefinition的合并

merged bean definition 它不是一个具体的类,而是 Spring 对 BeanDefinition 进行的一种合并操作。

在根据 BeanDefinition 创建 bean 的实例之前,会通过AbstractBeanFactory#getMergedLocalBeanDefinition()来将 child 和 parent bean definition 进行合并。

BeanDefinition 的 merge 操作的作用是什么?

答:对 BeanDefinition 进行 merge 操作时,会将 child 的属性与 parent 的属性进行合并,当有相同属性时,以 child 的为准。

而类似 propertyValues、constructor args 这种集合类的参数属性的话,就会取并集。

3、上面2个的共同子类

https://www.cnblogs.com/xfeiyun/p/15666295.html

区别

  • ScannedGenericBeanDefinitionAnnotatedGenericBeanDefinition 其实功能上是等价的,都是基于注解,区别在于:
    • AnnotatedGenericBeanDefinition只能用于已经被注册或被扫描到的类

ScannedGenericBeanDefinition

ScannedGenericBeanDefinition该类继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。用来描述@Component@Service@Controller等注解注释的bean

这个类不会提前加载bean类。而是从“.class”文件本身检索所有相关的元数据,用ASM ClassReader解析。它在功能上等价于

AnnotatedGenericBeanDefinition # AnnotatedGenericBeanDefinition (AnnotationMetadata)

但是通过已扫描的bean与已通过其他方式注册或检测的bean的类型进行区分。

它的源码很简单,就是多了一个属性:private final AnnotationMetadata metadata用来存储扫描进来的Bean的一些注解信息。

public class ScannedGenericBeanDefinition extends GenericBeanDefinition 
    implements AnnotatedBeanDefinition {

    /**
     * 当前 bean 的注解元数据
     */
    private final AnnotationMetadata metadata;

    // 它只有一个构造函数:必须传入MetadataReader
    public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
        Assert.notNull(metadataReader, "MetadataReader must not be null");
        this.metadata = metadataReader.getAnnotationMetadata();
        setBeanClassName(this.metadata.getClassName());
    }

    ...
}

AnnotatedGenericBeanDefinition

在基于注解驱动的Spring应用着,它使用得非常的多。因为获取注解信息非常的方便~

该类继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。

AnnotatedGenericBeanDefinition只能用于已经被注册或被扫描到的类(否则你手动new一个,它就不在容器里了,那就脱离管理了)

这个 GenericBeanDefinition 变体主要用于测试期望操作 AnnotatedBeanDefinition 的代码,例如Spring组件扫描支持中的策略实现(其中默认定义类是 ScannedGenericBeanDefinition },它也实现了 AnnotatedBeanDefinition 接口)。

public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition 
    implements AnnotatedBeanDefinition {

    /**
     * 当前 bean 的注解元数据
     */
    private final AnnotationMetadata metadata;

    /**
     * 储工厂方法的元数据
     */
    @Nullable
    private MethodMetadata factoryMethodMetadata;

    /**
     * 根据给定的 bean class 创建AnnotatedGenericBeanDefinition
     * @param beanClass the loaded bean class (已经加载的bean class)
     */
    public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
        setBeanClass(beanClass);
        this.metadata = AnnotationMetadata.introspect(beanClass);
    }

    /**
     * 为给定的注释元数据创建一个新的AnnotatedGenericBeanDefinition,
     * 允许基于asm的处理并避免bean类的早期加载。
     * 注意,此构造函数在功能上等价于ScannedGenericBeanDefinition,
     * 但是后者的语义表明,bean是专门通过组件扫描发现的,而不是通过其他方法。
     */
    public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
        Assert.notNull(metadata, "AnnotationMetadata must not be null");
        if (metadata instanceof StandardAnnotationMetadata) {
            setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
        }
        else {
            setBeanClassName(metadata.getClassName());
        }
        this.metadata = metadata;
    }

    ...
}

使用案例

AnnotatedBeanDefinition beanDefinition = 
    new AnnotatedGenericBeanDefinition(RootConfig.class);

// 就这么一下子,就把注解们都拿到了,简直不要太方便,简直可以当工具类来用
Set<String> annotationTypes = beanDefinition.getMetadata().getAnnotationTypes();

//[org.springframework.context.annotation.ComponentScan, org.springframework.context.annotation.Configuration]
System.out.println(annotationTypes); 

System.out.println(beanDefinition.isSingleton()); //true
System.out.println(beanDefinition.getBeanClassName()); //com.config.RootConfig

ConfigurationClassBeanDefinition

首先需要注意的是,它是 ConfigurationClassBeanDefinitionReader 的一个私有的静态内部类:这个类负责将 @Bean 注解的方法转换为对应的 ConfigurationClassBeanDefinition 类(非常的重要)

该内部类继承自 RootBeanDefinition,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述在标注 @Configuration 注解的类中,通过 @Bean 注解实例化的 Bean。

其功能特点如下:

  • 1、如果 @Bean 注解没有指定 Bean 的名字,默认会用方法的名字命名 Bean

  • 2、标注 @Configuration 注解的类会成为一个工厂类,而标注 @Bean 注解的方法会成为工厂方法,通过工厂方法实例化 Bean,而不是直接通过构造方法初始化。

  • 3、标注 @Bean 注解的类会使用构造方法自动装配(这里说的是类,第二点说的是方法)

Spring 初始化时,会用 GenericBeanDefinition 或是 ConfigurationClassBeanDefinition (用 @Bean 注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition

四、BeanDefinitionBuilder

BeanDefinitionBuilder:工具类,作用是快速创建一个BeanDefinition

使用它的好处是,可以进行方法的连缀。

没有特殊指明,创建的都是GenericBeanDefinition,源码非常的简单

public final class BeanDefinitionBuilder {

    /** -------- 各种获取BeanDefinitionBuilder的静态方法 -------------- */

    public static BeanDefinitionBuilder genericBeanDefinition() {
        return new BeanDefinitionBuilder(new GenericBeanDefinition());
    }

    public static BeanDefinitionBuilder genericBeanDefinition(String beanClassName) {
        BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
        builder.beanDefinition.setBeanClassName(beanClassName);
        return builder;
    }

    public static BeanDefinitionBuilder genericBeanDefinition(Class<?> beanClass) {
        BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
        builder.beanDefinition.setBeanClass(beanClass);
        return builder;
    }

    public static <T> BeanDefinitionBuilder genericBeanDefinition(Class<T> beanClass, Supplier<T> instanceSupplier) {
        BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
        builder.beanDefinition.setBeanClass(beanClass);
        builder.beanDefinition.setInstanceSupplier(instanceSupplier);
        return builder;
    }

    //...



}

使用案例

AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Child.class)
    .setRole(BeanDefinition.ROLE_APPLICATION)
    .setScope(BeanDefinition.SCOPE_SINGLETON)
    .addPropertyValue("name", "hare")
    .setLazyInit(false)
    //Spring5.0后提供的,可以自己书写函数,在里面做任意事情
    //bdf是个AbstractBeanDefinition
    .applyCustomizers((bdf) -> {
        AbstractBeanDefinition abdf = (AbstractBeanDefinition) bdf;
        abdf.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_NO);
    }).getRawBeanDefinition();


System.out.println(beanDefinition); //Generic bean: class [com.fsx.maintest.Child]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; d...

五、BeanDefinitionReader

1、接口介绍

BeanDefinitionReader:该接口的作用就是加载和注册 Bean

BeanDefinitionReader 可以将XML、注解等形式的bean配置信息解析读取进来,将其转换为 IoC 容器内部的数据结构:BeanDefinition。

在 Spring 中,Bean 一般来说都在配置文件中定义。而在配置的路径由在 web.xml 中定义(还有全注解的方式)。所以加载 Bean 的步骤大致就是:

  1. 加载资源,通过配置文件的路径(Location)加载配置文件(Resource)
  2. 解析资源,通过解析配置文件的内容得到 Bean。
public interface BeanDefinitionReader {

    /**
    * 返回 bean factory ,可用与注册 beanDefinition
    * 工厂是通过BeanDefinitionRegistry接口公开的,它封装了与bean定义处理相关的方法。
    * 注:大多数具体的 beanFactory 都实现了 BeanDefinitionRegistry
    */
    BeanDefinitionRegistry getRegistry();

    // 返回用于加载资源的 ResourceLoader(可以为null)
    @Nullable
    ResourceLoader getResourceLoader();

    // 加载Bean的类加载器
    @Nullable
    ClassLoader getBeanClassLoader();

    // 生成Bean名称的名字生成器(若没有指定名称的话,会调用它生成)
    BeanNameGenerator getBeanNameGenerator();


    // 核心方法,loadbean定义进来,然后注册到上面的register 里面去
    int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;

    int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;

}

2、继承体系

image-20220927214203781

AbstractBeanDefinitionReader:是一个抽象类,同时实现了EnvironmentCapable接口,提供环境的get和set方法。它实现了BeanDefinitionReader的一些通用方法,比如按照路径来读取Bean定义信息的方法→int loadBeanDefinitions(String location)。对于更为具体的方法,比如根据资源来读取Bean定义信息的方法→int loadBeanDefinitions(Resource resource),则交由子类来实现。

PropertiesBeanDefinitionReader:是一个具体实现类,可以从properties文件读取Bean定义信息。

XmlBeanDefinitionReader:具体实现类,可以从XML文件读取Bean定义信息。

GroovyBeanDefinitionReader:具体实现类,可以读取Groovy 语言写的Bean的定义信息。

其他的 BeanDefinitionReader

  • AnnotatedBeanDefinitionReader , 并不是 BeanDefinitionReader 的实现类,它没有继承任何类。在AnnotationConfigApplicationContext中使用到,AnnotatedBeanDefinitionReader 的构造方法中参数为BeanDefinitionRegistry。它的重要方法是register,用于获取一个或多个带有注解的具体类,之后将他们解析为BeanDefintion,之后注册到Registry中。

3、AbstractBeanDefinitionReader

它实现了一些基本的方法,但是核心方法 loadBeanDefinitions 是交给子类实现

public abstract class AbstractBeanDefinitionReader 
    implements EnvironmentCapable, BeanDefinitionReader {

    private final BeanDefinitionRegistry registry;

    @Nullable
    private ResourceLoader resourceLoader;

    @Nullable
    private ClassLoader beanClassLoader;

    // 会有环境变量
    private Environment environment;

    // 默认的名字生成器(类名首字母小写)
    private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();

    /*
     * 根据给定的 beanFactory 创建一个 AbstractBeanDefinitionReader。
     * 如果传入的 beanFactory 不仅实现了 BeanDefinitionRegistry ,还实现了 ResourceLoader 接口,
     * 那么它也将被用作默认的ResourceLoader。这通常是ApplicationContext实现的情况。
     *
     * 如果给定一个普通的BeanDefinitionRegistry,默认的ResourceLoader将是一个PathMatchingResourcePatternResolver。
     *
     * 如果给定的 beanFactory 也实现了 EnvironmentCapable,那么它的环境将被这个reader使用。
     * 否则,reader将初始化并使用StandardEnvironment。
     * 所有的ApplicationContext都是实现了EnvironmentCapable的,而普通的BeanFactory实现不是。
    */
    protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
        Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
        this.registry = registry;

        // Determine ResourceLoader to use.
        if (this.registry instanceof ResourceLoader) {
            this.resourceLoader = (ResourceLoader) this.registry;
        } else {
            // 注意这个处理
            this.resourceLoader = new PathMatchingResourcePatternResolver();
        }

        // Inherit Environment if possible
        // 如果注册器里有环境变量,就用它的 否则new一个标准的,它下面也提供了set方法可以设置
        if (this.registry instanceof EnvironmentCapable) {
            this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
        } else {
            this.environment = new StandardEnvironment();
        }
    }


    ...    
}

4、XmlBeanDefinitionReader

XmlBeanDefinitionReader:从xml中加载Bean定义信息

我们注解配置中@Configuration上也可以加上@ImportResource导入外置的xml配置文件。它由此方法ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromImportedResources处理,内部借助的就是XmlBeanDefinitionReader去解析它的

5、PropertiesBeanDefinitionReader

PropertiesBeanDefinitionReader:直接从properties文件或者Map里加载Bean

六、BeanDefinitionRegistry

保存bean定义的注册中心接口,例如 RootBeanDefinitionchildBeandefinition 实例。通常由beanfactory 实现内部工作与抽象定义层次结构

这是Spring's bean factory packages中封装bean定义注册的唯一接口。标准BeanFactory接口只涵盖对完全配置的工厂实例的访问

Spring core中实现该接口的有:

  • DefaultListableBeanFactory

  • GenericApplicationContext

1、接口源码

public interface BeanDefinitionRegistry extends AliasRegistry {

    //注册 BeanDefinition
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);

    //删除 BeanDefinition
    void removeBeanDefinition(String beanName);

    //获取 BeanDefinition
    BeanDefinition getBeanDefinition(String beanName);

    //判断该容器中是否包含指定的 BeanDefinition
    boolean containsBeanDefinition(String beanName);

    //获取该容器所有的 BeanDefinition
    String[] getBeanDefinitionNames();

    //获取该容器所有的 BeanDefinition 数量
    int getBeanDefinitionCount();

    //确定给定的bean名称是否已经在此注册中心中使用,
    //例如,是否有一个本地bean或别名在这个名称下注册。
    boolean isBeanNameInUse(String beanName);
}

2、DefaultListableBeanFactory实现

(1)registerBeanDefinition

注册的核心就是 this.beanDefinitionMap.put(beanName, beanDefinition);

bean定义的注册过程,其实就是把Bean定义,put进 beanDefinitionMap 中;另外在 beanDefinitionNamesSet<String> 中放入一个 bean name 缓存起来,表示标记bean name对应的Bean定义已解析

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, 
                    BeanDefinitionRegistry, 
                    Serializable {

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        //1、判断beanDefinition类型,如果是则要校验此bean定义。
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                //校验此bean定义。
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        // 2、获取容器中指定名称的BeanDefinition
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);

        // 3、如果容器中已有指定名称的BeanDefinition
        if (existingDefinition != null) {

            //判断是否允许重写BeanDefinition,如果不允许,则直接报错
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            //使用传入的 beanDefinition 替换原来的
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        // 3、如果容器中不含有指定名称的BeanDefinition
        else {
            //检查工厂的bean创建阶段是否已经开始,即是否有任何bean被标记为在此期间创建。
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                // 不能再修改启动时集合元素(对于稳定迭代),防止出现集合List<String> beanDefinitionNames线程安全问题
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    //更新容器的内部手动添加的单例集合manualSingletonNames
                    removeManualSingletonName(beanName);
                }
            }
            else {
                // Still in startup registration phase
                //还在启动注册阶段
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                //更新容器的内部手动添加的单例集合manualSingletonNames
                removeManualSingletonName(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (existingDefinition != null || containsSingleton(beanName)) {
            //重置所有指定beanName的BeanDefinition相关的缓存
            resetBeanDefinition(beanName);
        }
        else if (isConfigurationFrozen()) {
            clearByTypeCache();
        }
    }

}

七、不存在BeanDefinition的情况

需要说明的一点是:加入你是自己直接通过SingletonBeanRegistry#registerSingleton向容器手动注入Bean的,那么就不会存在这份Bean定义信息的,这点需要注意。

Spring内部有不少这样的例子(因为这种Bean非常简单,根本不需要定义信息):

  • beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
  • beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
  • bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
  • bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME, Collections.unmodifiableMap(attributeMap));

那我们注解的@Bean以及@Component的这么些bean定义都是谁去加载的呢? 需要注意的是这个就不属于它了。

@Bean都是@Configuration配置类里,统一由ConfigurationClassParser#parse()里去处理的(直接执行Method就行)
@Component这种组件统一由解析@ComponentScan的处理器的ComponentScanAnnotationParser(借助ClassPathBeanDefinitionScanner) 。参考文章:

Spring解析@ComponentScan注解分析(ComponentScanAnnotationParser、ClassPathBeanDefinitionScanner)


  目录