Spring源码解析系列之BeanDefinition

在Spring IOC源码分析过程中,会反复的提到一个类BeanDefinition。在Spring中,对于Bean的创建来源有很多种方式,比如,使用xml配置,使用@configration配置,使用@Bean主键等。不同的Bean还有着不同的依赖,如何来定义这些Bean呢,Spring提供了BeanDefinition来做这样的事情。

Bean的定义主要由BeanDefinition来描述的。作为Spring中用于包装Bean的数据结构,让小编来待着大家看看面纱下的真容吧。

BeanDefinition定义

首先就是BeanDefinition的定义:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement

从源码中给出的注释可以看出来,BeanDefinition作为定义Spring中Bean的接口,可以说是Bean的抽象数据结构,包括属性参数,构造器参数,以及具体实现的进一步信息。

BeanDefinition结构

先来看一下BeanDefinition的继承结构图,如下:

image.png

观看BeanDefinition的继承结构最大的感触就是,整个继承关系职责分明,层层叠进。如果仔细观看Spring源码的话,会发现这样的设计是随处可见。

一个BeanDefinition描述了一个Bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息。对于顶层接口BeanDefinition的设计,Spring的开发者们通过对于Bean定义描述需要具备的行为和功能进行分析建模,设计出一套统一抽象的模型。如果熟悉DDD的朋友会发现这是领域分析建模的成果。在Spring源码里面对抽象接口的设计比较完善且具备参考价值,有很多值得学习的地方。我们可以在阅读Spring源码的同时对于其中的一些设计进行分析和思考,然后总结出自己的方法,累积经验。

AbstractBeanDefinition抽象类为BeanDefinition接口的部分方法提供统一的实现。然后下面的子类是实际具备业务含义的类比如RootBeanDefinition、ChildBeanDefinition等是根据具体的业务需求实现或者重定义其中的某些行为(当然整个过程是在遵守BeanDefinition的领域边界内进行的)。下面会对这些类进行逐一的解析。

首先从类图中可以看出BeanDefinition继承了AttributeAccessor和BeanMetadataElement两个接口;稍微提一下这里应该是使用了接口隔离的原则,在Spring中也是可以随处可见这样的一个设计,这是为了更好的实现单一职责而做出的努力。

AttributeAccessor

主要用于定义附加和访问元数据的通用的接口

// 定义用于附加和访问元数据的通用的接口,来自任意对象
public interface AttributeAccessor {
    // 设置属性的值
    void setAttribute(String name, @Nullable Object value);
    // 获得指定属性名称的值,如果不存在返回null
    @Nullable
    Object getAttribute(String name);
    // 删除指定的name的属性,如果不存在则返回null
    @Nullable
    Object removeAttribute(String name);
    // 判断指定的属性名称是否存在,注意属性名称必须是唯一的
    boolean hasAttribute(String name);
    // 得到所有属性的名称
    String[] attributeNames();
}

BeanMetadataElement

元数据,返回Bean的来源,BeanMetadataElement只有一个方法,该方法返回可配置源的对象。

这个方法在@Configuration中使用较多,因为他会被代理

public interface BeanMetadataElement {
    // 返回可配置源对象
    @Nullable
    default Object getSource() {
        return null;
    }
}

通过对AttributeAccessor和BeanMetadataElement 两个接口的介绍基本上可以看出来,BeanDefinition实现了这两个接口其实就是具备对应的行为和属性,主要是对于属性和参数的存储和相关的源对象的保存。

BeanDefinition源码

介绍完AttributeAccessor和BeanMetadataElement 的接口(前面也说了这是一种单一职责的体现)。BeanDefinition仅仅是一个最简单的接口,主要功能是允许BeanFactoryPostProcessor,例如PropertyPlaceHolderConfigure能够检索并修改属性值和别的Bean的元数据,下面来看一下BeanDefinition的源码实际上包含哪些内容。(Spring的注释比较详细,这里考虑文章篇幅,部分注解自己做了一下删减)

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    //表示bean的作用域是单例还是原型模式
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
    /**
     * bean的角色
     */
    // 默认,为应用程序定义
    int ROLE_APPLICATION = 0;
    // 做为大量配置的一部分(支持、扩展类)  实际上就是说,我这个Bean是用户的,是从配置文件中过来的
    int ROLE_SUPPORT = 1;
    // 指内部工作的基础构造  实际上是说我这Bean是Spring自己的,和你用户没有一毛钱关系
    int ROLE_INFRASTRUCTURE = 2;


    // Modifiable attributes
    // 如果存在父类bean的话将名称设置进去
    void setParentName(@Nullable String parentName);
    @Nullable
    String getParentName();

    // 指定这个bean定义的bean类名。类名可以在bean工厂后期处理时修改,通常用解析后的类名替换原来的类名。
    void setBeanClassName(@Nullable String beanClassName);
    @Nullable
    String getBeanClassName();

    // 上面设置的原型还是单例SCOPE_SINGLETON or SCOPE_PROTOTYPE
    void setScope(@Nullable String scope);
    @Nullable
    String getScope();

    // 设置是否懒加载,如果设置为false容器启动的时候就会加载单例bean,true只有当需要的时候才会加载bean
    void setLazyInit(boolean lazyInit);
    boolean isLazyInit();

    /**
     * dependsOn一般用于两个bean之间没有显示依赖,但后一个Bean需要用到前一个Bean执行初始方法后的结果。例如在< bean id=“a” dependsOn=“b”/> 时
     * 在初始化a时首先先初始化b,在销毁b之前会先销毁a。
     */
    void setDependsOn(@Nullable String... dependsOn);
    @Nullable
    String[] getDependsOn();

    // 这个Bean是否允许被自动注入到别的地方去(默认都是被允许的)
    // 注意:此标志只影响按类型装配,不影响byName的注入方式的
    // no:不使用自动装配,必须通过ref元素指定依赖,为autowire默认值。
    // byName:使用属性名自动装配,如果存在一个与指定属性名相同类型的bean则自动装配,如果有多个,则抛
    //  出异常。
    // byType:根据类型自动状态,如果存在与指定属性类型相同的bean,则自动装配,如果有多个,则抛出异常。
    // constructor:与byType类似,不同之处在于它使用的是构造器的参数类型。
    // autodetect:通过bean的自省机制来决定是使用constructor还是byType来进行自动装配。如果有默认构造
    // 器,则使用byType,否则使用constructor。
    void setAutowireCandidate(boolean autowireCandidate);
    boolean isAutowireCandidate();

    //如果其他对象按照类型自动装配时发现有多个符合类型的多个实现bean,如果bean的primary属性为true,
    //则以primary为true的优先,当然如果有多个primary为true,则抛出异常。
    // @Primary
    void setPrimary(boolean primary);
    boolean isPrimary();

    // 设置bean的factoryBeanName
    void setFactoryBeanName(@Nullable String factoryBeanName);
    @Nullable
    String getFactoryBeanName();

    //指定工厂方法~
    void setFactoryMethodName(@Nullable String factoryMethodName);
    @Nullable
    String getFactoryMethodName();

    // 返回bean构造函数参数
    ConstructorArgumentValues getConstructorArgumentValues();
    default boolean hasConstructorArgumentValues() {
        return !getConstructorArgumentValues().isEmpty();
    }

    // 属性集合
    MutablePropertyValues getPropertyValues();
    default boolean hasPropertyValues() {
        return !getPropertyValues().isEmpty();
    }

    /**
     * Set the name of the initializer method.
     * @since 5.1
     */
    void setInitMethodName(@Nullable String initMethodName);

    /**
     * Return the name of the initializer method.
     * @since 5.1
     */
    @Nullable
    String getInitMethodName();

    /**
     * Set the name of the destroy method.
     * @since 5.1
     */
    void setDestroyMethodName(@Nullable String destroyMethodName);

    /**
     * Return the name of the destroy method.
     * @since 5.1
     */
    @Nullable
    String getDestroyMethodName();

    // 对应上面设置的角色
    void setRole(int role);
    int getRole();

    // @Description
    void setDescription(@Nullable String description);
    @Nullable
    String getDescription();

    // Read-only attributes

    ResolvableType getResolvableType();
    boolean isSingleton();
    boolean isPrototype();

    // 返回bean对象是否是抽象类,抽象类不需要实例化
    boolean isAbstract();

    /**
     * Return a description of the resource that this bean definition
     * came from (for the purpose of showing context in case of errors).
     */
    @Nullable
    String getResourceDescription();

    //返回原始BeanDefinition,如果没有则返回@null
    // 若这个Bean定义被代理、修饰过  这个方法可以返回原始的
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();

}

这里的话可以仔细看看BeanDefinition的设计,对于Bean的描述,Spring是如何通过BeanDefinition这样一个对象来对其进行描述的。后期就是通过描述对象来决定如何实例化Bean对象。其实可以思考一下如果是我们来设计这样一个类会如何设计,spring又是如何设计,这之间的差距在什么地方。

当然这整个过程完全对应这<bean/>中的相关的配置属性,或者是@bean中的相关注解一一对应的。

AbstractBeanDefinition源码

考虑到整个源码量比较大,这里分开展示出来解析

 // 默认单例
    public static final String SCOPE_DEFAULT = "";

    // 自动装配的一些常量
    public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
    public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
    public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
    public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
    @Deprecated
    public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;

SCOPE_DEFAULT 设置默认的Bean的Scope,对应BeanDefinition中ConfigurableBeanFactory.SCOPE_SINGLETON和ConfigurableBeanFactory.SCOPE_PROTOTYPE

设置的自动装配的相关常量:

  • no:不使用自动装配,必须通过ref元素指定依赖,为autowire默认值。
  • byName:使用属性名自动装配,如果存在一个与指定属性名相同类型的bean则自动装配,如果有多个,则抛出异常。
  • byType:根据类型自动状态,如果存在与指定属性类型相同的bean,则自动装配,如果有多个,则抛出异常。
  • constructor:与byType类似,不同之处在于它使用的是构造器的参数类型。
  • autodetect:通过bean的自省机制来决定是使用constructor还是byType来进行自动装配。如果有默认构造器,则使用byType,否则使用constructor。
// 检查依赖是否合法,默认不进行检查
    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;

对依赖进行按需检查,根据不同的配置可以实现不同的检查方式。对应的解析如以上代码注释所示。

/**
     * Constant that indicates the container should attempt to infer the
     * {@link #setDestroyMethodName destroy method name} for a bean as opposed to
     * explicit specification of a method name. The value {@value} is specifically
     * designed to include characters otherwise illegal in a method name, ensuring
     * no possibility of collisions with legitimately named methods having the same
     * name.
     * <p>Currently, the method names detected during destroy method inference
     * are "close" and "shutdown", if present on the specific bean class.
     * 若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字,目前来说,推断的销毁方法的名字一般为close或是shutdown
     *(即未指定Bean的销毁方法,但是内部定义了名为close或是shutdown的方法,则容器推断其为销毁方法)
     */
    public static final String INFER_METHOD = "(inferred)";

    // bean的class对象或者类的权限定名
    @Nullable
    private volatile Object beanClass;

    // 默认单例
    @Nullable
    private String scope = SCOPE_DEFAULT;
    // 不然不是抽象类
    private boolean abstractFlag = false;
    // 默认不是懒加载
    @Nullable
    private Boolean lazyInit;
    // 默认不进行自动装配
    private int autowireMode = AUTOWIRE_NO;
    // 默认不进行依赖检查
    private int dependencyCheck = DEPENDENCY_CHECK_NONE;
    @Nullable
    private String[] dependsOn;
    // autowire-candidate属性设置为false,这样容器在查找自动装配对象时,将不考虑该bean,
    // 备注:并不影响本身注入其它的Bean
    private boolean autowireCandidate = true;
    // 默认不是主bean
    private boolean primary = false;
    //用于记录Qualifier,对应子元素qualifier=======这个字段有必要解释一下
    // 唯一向这个字段放值的方法为本类的:public void addQualifier(AutowireCandidateQualifier qualifier)    copyQualifiersFrom这个不算,那属于拷贝
    // 调用处:AnnotatedBeanDefinitionReader#doRegisterBean  但是Spring所有调用处,qualifiers字段传的都是null~~~~~~~~~尴尬
    // 通过我多放跟踪发现,此处这个字段目前【永远】不会被赋值(除非我们手动调用对应方法为其赋值)   但是有可能我才疏学浅,若有知道的  请告知,非常非常感谢  我考虑到它可能是预留字段~~~~
    // 我起初以为这样可以赋值:
    //@Qualifier("aaa")
    //@Service
    //public class HelloServiceImpl   没想到,也是不好使的,Bean定义里面也不会有值
    // 因此对应的方法getQualifier和getQualifiers 目前应该基本上都返回null或者[]
    private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();

    //用于记录Qualifier,对应子元素qualifier=======这个字段有必要解释一下
    // 唯一向这个字段放值的方法为本类的:public void addQualifier(AutowireCandidateQualifier qualifier)    copyQualifiersFrom这个不算,那属于拷贝
    // 调用处:AnnotatedBeanDefinitionReader#doRegisterBean  但是Spring所有调用处,qualifiers字段传的都是null~~~~~~~~~尴尬
    // 通过我多放跟踪发现,此处这个字段目前【永远】不会被赋值(除非我们手动调用对应方法为其赋值)   但是有可能我才疏学浅,若有知道的  请告知,非常非常感谢  我考虑到它可能是预留字段~~~~
    // 我起初以为这样可以赋值:
    //@Qualifier("aaa")
    //@Service
    //public class HelloServiceImpl   没想到,也是不好使的,Bean定义里面也不会有值
    // 因此对应的方法getQualifier和getQualifiers 目前应该基本上都返回null或者[]
    private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);
    //我理解为通过这个函数的逻辑初始化Bean,而不是构造函数或是工厂方法(相当于自己去实例化,而不是交给Bean工厂)
    @Nullable
    private Supplier<?> instanceSupplier;
    //是否允许访问非public方法和属性,应用于构造函数、工厂方法、init、destroy方法的解析 默认是true,表示啥都可以访问
    private boolean nonPublicAccessAllowed = true;
    // 是否以一种宽松的模式解析构造函数,默认为true(宽松和严格体现在类型匹配上)
    private boolean lenientConstructorResolution = true;
    //工厂类名(注意是String类型,不是Class类型) 对应bean属性factory-method
    @Nullable
    private String factoryBeanName;
    //工厂方法名(注意是String类型,不是Method类型)
    @Nullable
    private String factoryMethodName;
    //记录构造函数注入属性,对应bean属性constructor-arg
    @Nullable
    private ConstructorArgumentValues constructorArgumentValues;
    
    //Bean属性的名称以及对应的值,这里不会存放构造函数相关的参数值,只会存放通过setter注入的依赖
    @Nullable
    private MutablePropertyValues propertyValues;
    //方法重写的持有者,记录lookup-method、replaced-method元素  @Lookup等
    @Nullable
    private MethodOverrides methodOverrides;

    //init函数的名字
    @Nullable
    private String initMethodName;
    //destory函数的名字
    @Nullable
    private String destroyMethodName;
    //是否执行init-method,程序设置
    private boolean enforceInitMethod = true;
    private boolean enforceDestroyMethod = true;

    //是否是合成类(是不是应用自定义的,例如生成AOP代理时,会用到某些辅助类,这些辅助类不是应用自定义的,这个就是合成类)
    //创建AOP时候为true
    private boolean synthetic = false;
    
    //Bean的角色,为用户自定义Bean
    private int role = BeanDefinition.ROLE_APPLICATION;

    // Bean的描述信息
    @Nullable
    private String description;
    //the resource that this bean definition came from
    // 这个Bean哪儿来的
    @Nullable
    private Resource resource;

  • MutablePropertyValues:对于这个类存放的是Bean相关的属性值,就是get/set方法对于的值。

我仔细观察这里的对象主要是分为两大类,

  1. 是对Bean的一些配置的描述,比如如何创建Bean,或者Bean是否具备某些特性;
  2. 是Bean自身的属性值的定义MutablePropertyValues

我感觉Spring的这种设计还是比较符合类组合的思想,将不同功能的类相互组合最后完成对于一个Bean的详细描述,可以说是从创建-》初始化-》销毁。贯穿了Bean在Spring中整个生命周期的一些配置和描述吧。

总结一下以上的AbstractBeanDefinition具备的基本属性值,并对其进行了注释,其中也参考了相关资料。通过源码可以了解到AbstractBeanDefinition定义了Bean描述的属性,通过这个类可以看到对bean描述的相关属性的默认配置。

对于AbstractBeanDefinition抽象类其主要还是为BeanDefinition接口实现一套通用的属性描述。为具体的子类如GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition实现提供更多的便捷,将公共的部分提取到抽象类中实现。这个应该是抽象类使用的比较多的一种场景吧。当然具体关于抽象类和接口直接的异同优劣这里不详细阐述。

接下来看一下具体衍生出来的实现类了,先看一下GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition。他们都是直接实现了AbstractBeanDefinition。

image.png

GenericBeanDefinition

GenericBeanDefinition是标准BeanDefinition的实现类,和任何其他Bean定义一样除了具有可选的构造函数参数值和属性值外,还可以通过设置“parentName”来设置parent BeanDefinition。源码如下所示:

@SuppressWarnings("serial")
public class GenericBeanDefinition extends AbstractBeanDefinition {

    @Nullable
    private String parentName;
    /**
     * Create a new GenericBeanDefinition, to be configured through its bean
     * properties and configuration methods.
     * @see #setBeanClass
     * @see #setScope
     * @see #setConstructorArgumentValues
     * @see #setPropertyValues
     */
    public GenericBeanDefinition() {
        super();
    }

    /**
     * Create a new GenericBeanDefinition as deep copy of the given
     * bean definition.
     * @param original the original bean definition to copy from
     */
    public GenericBeanDefinition(BeanDefinition original) {
        super(original);
    }


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

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


    @Override
    public AbstractBeanDefinition cloneBeanDefinition() {
        return new GenericBeanDefinition(this);
    }

    @Override
    public boolean equals(@Nullable Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof GenericBeanDefinition)) {
            return false;
        }
        GenericBeanDefinition that = (GenericBeanDefinition) other;
        return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other));
    }

    @Override
    public String toString() {
        if (this.parentName != null) {
            return "Generic bean with parent '" + this.parentName + "': " + super.toString();
        }
        return "Generic bean: " + super.toString();
    }

}

GenericBeanDefinition的源码比较简单,只是增加了一个parentName的属性值,其余的实现都是在AbstractBeanDefinition中。在xml中配置的bean,被添加进来的时候都是GenericBeanDefinition类型。如下

// BeanDefinitionParserDelegate.java
    public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, @Nullable BeanDefinition containingBean) {

        // 省略代码部分代码

        try {
            //1. 根据类名创建对应的BeanDefinition对象
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);

            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

            parseMetaElements(ele, bd);
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

            parseConstructorArgElements(ele, bd);
            parsePropertyElements(ele, bd);
            parseQualifierElements(ele, bd);

            bd.setResource(this.readerContext.getResource());
            bd.setSource(extractSource(ele));

            return bd;
        }
        catch (ClassNotFoundException ex) {
            error("Bean class [" + className + "] not found", ele, ex);
        }
        catch (NoClassDefFoundError err) {
            error("Class that bean class [" + className + "] depends on not found", ele, err);
        }
        catch (Throwable ex) {
            error("Unexpected failure during bean definition parsing", ele, ex);
        }
        finally {
            this.parseState.pop();
        }

        return null;
    }

BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)方法中有着这么一行代码。(关于BeanDefinitionParserDelegate在后面spring BeanDefinition注册中会详细的讲解)

//1. 根据类名创建对应的BeanDefinition对象
AbstractBeanDefinition bd = createBeanDefinition(className, parent);

我们在看一下这行代码createBeanDefinition,跟踪进去看一下

    //  BeanDefinitionParserDelegate.java
    protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
            throws ClassNotFoundException {

        return BeanDefinitionReaderUtils.createBeanDefinition(
                parentName, className, this.readerContext.getBeanClassLoader());
    }

我们可以看到BeanDefinitionReaderUtils这个工具类,主要是通过他来创建具体的BeanDefinition对象

   //BeanDefinitionReaderUtils.java
    public static AbstractBeanDefinition createBeanDefinition(
            @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

        GenericBeanDefinition bd = new GenericBeanDefinition();
        bd.setParentName(parentName);
        if (className != null) {
            if (classLoader != null) {
                bd.setBeanClass(ClassUtils.forName(className, classLoader));
            }
            else {
                bd.setBeanClassName(className);
            }
        }
        return bd;
    }

到这里基本上可以看到在xml中配置的Bean,最初会被解析成GenericBeanDefinition。

刚刚说到GenericBeanDefinition的parentName,这里要解释一下parent指向的类不是子类继承父类的意思。对于这个parent的必要条件这里提一下主要两点:

  1. 子Bean必须与父Bean保持兼容,也就是说子Bean中必须有父Bean定义的所有属性
  2. 父Bean必须是抽象Bean或者定义了lazy-init=true也就是不让Bean工厂实例化该Bean

ChildBeanDefinition

ChildBeanDefinition继承父类设置的Bean的定义,对父Bean(RootBeanDefinition)定义有固定的依赖关系。他将从父Bean继承构造函数的参数,属性值和可覆盖的方法和选择添加新的值。

注意:Spring 2.5以来,注册bean的首选方式定义是GenericBeanDefinition类,允许动态定义父依赖GenericBeanDefinition#setParentName,这有效地在大多数用例中替代ChildBeanDefinition类。

public class ChildBeanDefinition extends AbstractBeanDefinition {

    @Nullable
    private String parentName;

从源码中也可以看到ChildBeanDefinition基本上和GenericBeanDefinition类似。按照源码中的注释来看,基本上是推荐使用GenericBeanDefinition来替换ChildBeanDefinition了。

RootBeanDefinition

定义一个可合并的Bean定义,在Spring BeanFactory运行期间返回特定的Bean。它可能是从多个彼此继承的原始bean定义创建的,通常还是建议使用GenericBeanDefinition。

public class RootBeanDefinition extends AbstractBeanDefinition {
    // 包含了Bean的名称,别名,BeanDefinition
    @Nullable
    private BeanDefinitionHolder decoratedDefinition;
    // 查看Bean注解信息
    @Nullable
    private AnnotatedElement qualifiedElement;

    // 确定是否需要进行合并
    /** Determines if the definition needs to be re-merged. */
    volatile boolean stale;

    // 允许合并
    boolean allowCaching = true;
    // 工厂方法是否唯一
    boolean isFactoryMethodUnique;
    // 用于反射
    @Nullable
    volatile ResolvableType targetType;

    /** Package-visible field for caching the determined Class of a given bean definition. */
    @Nullable
    volatile Class<?> resolvedTargetType;

    /** Package-visible field for caching if the bean is a factory bean. */
    @Nullable
    volatile Boolean isFactoryBean;

    /** Package-visible field for caching the return type of a generically typed factory method. */
    @Nullable
    volatile ResolvableType factoryMethodReturnType;

    /** Package-visible field for caching a unique factory method candidate for introspection. */
    @Nullable
    volatile Method factoryMethodToIntrospect;

    /** Package-visible field for caching a resolved destroy method name (also for inferred). */
    @Nullable
    volatile String resolvedDestroyMethodName;

    /** Common lock for the four constructor fields below. */
    final Object constructorArgumentLock = new Object();

    /** Package-visible field for caching the resolved constructor or factory method. */
    @Nullable
    Executable resolvedConstructorOrFactoryMethod;

    /** Package-visible field that marks the constructor arguments as resolved. */
    boolean constructorArgumentsResolved = false;

    /** Package-visible field for caching fully resolved constructor arguments. */
    @Nullable
    Object[] resolvedConstructorArguments;

    /** Package-visible field for caching partly prepared constructor arguments. */
    @Nullable
    Object[] preparedConstructorArguments;

    /** Common lock for the two post-processing fields below. */
    final Object postProcessingLock = new Object();

    /** Package-visible field that indicates MergedBeanDefinitionPostProcessor having been applied. */
    boolean postProcessed = false;

    /** Package-visible field that indicates a before-instantiation post-processor having kicked in. */
    @Nullable
    volatile Boolean beforeInstantiationResolved;

    @Nullable
    private Set<Member> externallyManagedConfigMembers;

    @Nullable
    private Set<String> externallyManagedInitMethods;

    @Nullable
    private Set<String> externallyManagedDestroyMethods;
    。。。。省略部分代码
    }

分析RootBeanDefiniiton的属性可以发现他对AbstractBeanDefinition做了新增,主要是针对一下几点:

  1. 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
  2. Bean的注解(AnnotatedElement)
  3. 具体的工厂方法(Class类型),包括工厂方法的返回类型,工厂方法的Method对象
  4. 构造函数、构造函数形参类型
  5. Bean的class对象

可以看到,RootBeanDefinition与AbstractBeanDefinition是互补关系,RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本完善

关于RootBeanDefiniiton还有一个概念也很重要,那就是getMergedBeanDefinition,在Spring里面有一个很重要的代码如下:

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

要是阅读源码细心的朋友应该在Spring里面都见过类似的代码。那么这行代码具体是在做什么呢,下面详细分析一下。

MergedBeanDefinition生成

我们先来看一下AbstractBeanFactory#getMergedLocalBeanDefinition的代码,已这个为切入点,分析一下MergedBeanDefinition生成过程

    protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
        // Quick check on the concurrent map first, with minimal locking.
        RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
        if (mbd != null && !mbd.stale) {
            return mbd;
        }
        return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
    }

上面的代码首先尝试从缓存中获取RootBeanDefinition,如果没有再通过getMergedBeanDefinition(beanName, getBeanDefinition(beanName))方法生成。其实可以看到核心代码在这里,我们一起跟踪进去看看。

  protected RootBeanDefinition getMergedBeanDefinition(
            String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
            throws BeanDefinitionStoreException {
        // 加锁防止出现并发问题
        synchronized (this.mergedBeanDefinitions) {
            RootBeanDefinition mbd = null;
            RootBeanDefinition previous = null;

            // Check with full lock now in order to enforce the same merged instance.
            if (containingBd == null) {
                mbd = this.mergedBeanDefinitions.get(beanName);
            }

            if (mbd == null || mbd.stale) {
                previous = mbd;
                // 判断db是否有parentname,如果没有直接返回bd的克隆
                // 当没有parentname的时候bd主要有两种类型
                // 1.一个独立的GenericBeanDefinition
                // 2.一个RootBeanDefinition
                if (bd.getParentName() == null) {
                    // Use copy of given root bean definition.
                    if (bd instanceof RootBeanDefinition) {
                        mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                    }
                    else {
                        mbd = new RootBeanDefinition(bd);
                    }
                }
                else {
                    // Child bean definition: needs to be merged with parent.
                    BeanDefinition pbd;
                    try {
                        String parentBeanName = transformedBeanName(bd.getParentName());
                        // 通过递归的方式因为bd有parent,他parent也可能有prent所以需要使用递归的方式
                        if (!beanName.equals(parentBeanName)) {
                            pbd = getMergedBeanDefinition(parentBeanName);
                        }
                        else {
                            BeanFactory parent = getParentBeanFactory();
                            if (parent instanceof ConfigurableBeanFactory) {
                                pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
                            }
                            else {
                                throw new NoSuchBeanDefinitionException(parentBeanName,
                                        "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
                                        "': cannot be resolved without a ConfigurableBeanFactory parent");
                            }
                        }
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
                                "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
                    }
                    // Deep copy with overridden values.
                    mbd = new RootBeanDefinition(pbd);
                    mbd.overrideFrom(bd);
                }

                // Set default singleton scope, if not configured before.
                if (!StringUtils.hasLength(mbd.getScope())) {
                    mbd.setScope(SCOPE_SINGLETON);
                }

                // A bean contained in a non-singleton bean cannot be a singleton itself.
                // Let's correct this on the fly here, since this might be the result of
                // parent-child merging for the outer bean, in which case the original inner bean
                // definition will not have inherited the merged outer bean's singleton status.
                if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                    mbd.setScope(containingBd.getScope());
                }

                // Cache the merged bean definition for the time being
                // (it might still get re-merged later on in order to pick up metadata changes)
                if (containingBd == null && isCacheBeanMetadata()) {
                    this.mergedBeanDefinitions.put(beanName, mbd);
                }
            }
            if (previous != null) {
                copyRelevantMergedBeanDefinitionCaches(previous, mbd);
            }
            return mbd;
        }
    }

从上面的代码可以看出来,该过程是通过递归使用getMergedBeanDefinition(),将parent放置到中间pbd中,最后通过mbd = new RootBeanDefinition(pbd);将parent中属性和相关参数设置到一个最终的RootBeanDefinition中。主要做的事情下面几步:

  • 判断BeanDefinition是否有parentname,如果没有可能会是一个GenericBeanDefinition或者RootBeanDefinition。直接将BeanDefinition返回即可
  • 如果有parentName,通过递归的方式将RootBeanDefinition返回,最后通过new RootBeanDefinition(pbd);将父BeanDefinition和子BeanDefinition进行合并,返回一个新的RootBeanDefinition

下面在看一下RootBeanDefinition(BeanDefinition original)的构造方法,我们看看他是否真的可以将参数original属性和参数进行合并。

    RootBeanDefinition(BeanDefinition original) {
        super(original);
    }

在看一下父类AbstractBeanDefinition的构造函数

 // AbstractBeanDefinition.java
    /**
     * Create a new AbstractBeanDefinition as a deep copy of the given
     * bean definition.
     * @param original the original bean definition to copy from
     */
    protected AbstractBeanDefinition(BeanDefinition original) {
        setParentName(original.getParentName());
        setBeanClassName(original.getBeanClassName());
        setScope(original.getScope());
        setAbstract(original.isAbstract());
        setFactoryBeanName(original.getFactoryBeanName());
        setFactoryMethodName(original.getFactoryMethodName());
        setRole(original.getRole());
        setSource(original.getSource());
        copyAttributesFrom(original);

        if (original instanceof AbstractBeanDefinition) {
            AbstractBeanDefinition originalAbd = (AbstractBeanDefinition) original;
            if (originalAbd.hasBeanClass()) {
                setBeanClass(originalAbd.getBeanClass());
            }
            if (originalAbd.hasConstructorArgumentValues()) {
                setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues()));
            }
            if (originalAbd.hasPropertyValues()) {
                setPropertyValues(new MutablePropertyValues(original.getPropertyValues()));
            }
            if (originalAbd.hasMethodOverrides()) {
                setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides()));
            }
            Boolean lazyInit = originalAbd.getLazyInit();
            if (lazyInit != null) {
                setLazyInit(lazyInit);
            }
            setAutowireMode(originalAbd.getAutowireMode());
            setDependencyCheck(originalAbd.getDependencyCheck());
            setDependsOn(originalAbd.getDependsOn());
            setAutowireCandidate(originalAbd.isAutowireCandidate());
            setPrimary(originalAbd.isPrimary());
            copyQualifiersFrom(originalAbd);
            setInstanceSupplier(originalAbd.getInstanceSupplier());
            setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed());
            setLenientConstructorResolution(originalAbd.isLenientConstructorResolution());
            setInitMethodName(originalAbd.getInitMethodName());
            setEnforceInitMethod(originalAbd.isEnforceInitMethod());
            setDestroyMethodName(originalAbd.getDestroyMethodName());
            setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod());
            setSynthetic(originalAbd.isSynthetic());
            setResource(originalAbd.getResource());
        }
        else {
            setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues()));
            setPropertyValues(new MutablePropertyValues(original.getPropertyValues()));
            setLazyInit(original.isLazyInit());
            setResourceDescription(original.getResourceDescription());
        }
    }

到这里基本上可以肯定了,这个构造方法其实就是将给定的BeanDefinition参数做一个深度拷贝,生成一个新的BeanDefinition对象。算是完全验证了我们上面对MergedBeanDefinition生成过程的分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值