Java架构师知识 潜水
  • 2发帖数
  • 2主题数
  • 0关注数
  • 0粉丝
开启左侧

面试官常问的:Spring源码之BeanDefinition源码解析

[复制链接]
Java架构师知识 发表于 2021-8-13 09:00:00 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
前言

在Spring IOC源码分析过程中,会反复的提到一个类BeanDefinition。在Spring中,对于Bean的创建泉源有很多种方式,比如,使用xml配置,使用@configration配置,使用@Bean主键等。不同的Bean还有着不同的依赖,如何来定义这些Bean呢,Spring提供了BeanDefinition来做如许的事情。
Bean的定义重要由BeanDefinition来描述的。作为Spring中用于包装Bean的数据结构,让小编来待着大家看看面纱下的真容吧。

BeanDefinition定义
首先就是BeanDefinition的定义:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement1.
从源码中给出的注释可以看出来,BeanDefinition作为定义Spring中Bean的接口,可以说是Bean的抽象数据结构,包罗属性参数,构造器参数,以及详细实现的进一步信息。

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


                               
登录/注册后可看大图

观看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();}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.BeanMetadataElement

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

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

public interface BeanMetadataElement {    // 返回可配置源对象    @Nullable    default Object getSource() {        return null;    }}1.2.3.4.5.6.7.
通过对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();}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.
这里的话可以仔细看看BeanDefinition的设计,对于Bean的描述,Spring是如何通过BeanDefinition如许一个对象来对其进行描述的。后期就是通过描述对象来决定如何实例化Bean对象。其实可以思索一下如果是我们来设计如许一个类会如何设计,spring又是如何设计,这之间的差距在什么地方。

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

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

   1.// 默认单例    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;1.2.3.4.5.6.7.8.9.10.
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。
1.  // 检查依赖是否正当,默认不进行检查    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; 1.2.3.4.5.6.7.8.
对依赖进行按需检查,根据不同的配置可以实现不同的检查方式。对应的解析如以上代码注释所示。

/**     * 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.     *
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 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 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;1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106. 1.
(注释相关内容复制网上 【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...))


  • MutablePropertyValues:对于这个类存放的是Bean相关的属性值,就是get/set方法对于的值。
我仔细观察这里的对象重要是分为两大类,


  • 是对Bean的一些配置的描述,比如如何创建Bean,或者Bean是否具备某些特性;
  • 是Bean自身的属性值的定义MutablePropertyValues
我感觉Spring的这种设计还是比力符合类组合的思想,将不同功能的类相互组合最后完成对于一个Bean的详细描述,可以说是从创建-》初始化-》烧毁。贯穿了Bean在Spring中整个生命周期的一些配置和描述吧。

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

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

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


                               
登录/注册后可看大图

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 &#39;" + this.parentName + "&#39;: " + super.toString();        }        return "Generic bean: " + super.toString();    }} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.
GenericBeanDefinition的源码比力简朴,只是增长了一个parentName的属性值,其余的实现都是在AbstractBeanDefinition中。在xml中配置的bean,被添加进来的时候都是GenericBeanDefinition类型。如下

1.   // 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;    } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.
BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)方法中有着这么一行代码。(关于BeanDefinitionParserDelegate在后面spring BeanDefinition注册中会详细的讲解)

//1. 根据类名创建对应的BeanDefinition对象AbstractBeanDefinition bd = createBeanDefinition(className, parent);1.2.
我们在看一下这行代码createBeanDefinition,跟踪进去看一下

1.   //  BeanDefinitionParserDelegate.java    protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)            throws ClassNotFoundException {        return BeanDefinitionReaderUtils.createBeanDefinition(                parentName, className, this.readerContext.getBeanClassLoader());    }1.2.3.4.5.6.7.
我们可以看到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;    } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.
到这里基本上可以看到在xml中配置的Bean,最初会被解析成GenericBeanDefinition。

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


  • 子Bean必须与父Bean保持兼容,也就是说子Bean中必须有父Bean定义的所有属性
  • 父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; 1.2.3.4.5.
从源码中也可以看到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 externallyManagedConfigMembers;    @Nullable    private Set externallyManagedInitMethods;    @Nullable    private Set externallyManagedDestroyMethods;    。。。。省略部门代码    } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.
分析RootBeanDefiniiton的属性可以发现他对AbstractBeanDefinition做了新增,重要是针对一下几点:(参考 【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...))


  • 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
  • Bean的注解(AnnotatedElement)
  • 详细的工厂方法(Class类型),包罗工厂方法的返回类型,工厂方法的Method对象
  • 构造函数、构造函数形参类型
  • Bean的class对象
可以看到,RootBeanDefinition与AbstractBeanDefinition是互补关系,RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本美满

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

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);1.
要是阅读源码细心的朋侪应该在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));    }1.2.3.4.5.6.7.8.
上面的代码首先尝试从缓存中获取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 &#39;" + parentBeanName + "&#39; is equal to bean name &#39;" + beanName +                                        "&#39;: cannot be resolved without a ConfigurableBeanFactory parent");                            }                        }                    }                    catch (NoSuchBeanDefinitionException ex) {                        throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,                                "Could not resolve parent bean definition &#39;" + bd.getParentName() + "&#39;", 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&#39;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&#39;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;        }    } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.
从上面的代码可以看出来,该过程是通过递归使用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);    } 1.2.3.
在看一下父类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());        }    } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.
到这里基本上可以肯定了,这个构造方法其实就是将给定的BeanDefinition参数做一个深度拷贝,生成一个新的BeanDefinition对象。算是完全验证了我们上面对MergedBeanDefinition生成过程的分析。

最后


                               
登录/注册后可看大图

另外还整理成了40多套PDF文档:全套的Java面试宝典手册,“性能调优+微服务架构+并发编程+开源框架+分布式”等七大面试专栏,包罗Tomcat、JVM、MySQL、SpringCloud、SpringBoot、Dubbo、并发、Spring、SpringMVC、MyBatis、Zookeeper、Ngnix、Kafka、MQ、Redis、MongoDB、memcached等等。如果你对这个感兴趣,小编可以免费分享。
资料获取方式:关注小编+转发文章+私信【面试题】获取上述资料~
重要的事情说三遍,转发+转发+转发,一定要记得转发哦!!!

精彩评论1

00爬行的蜗牛8 发表于 2021-8-13 13:53:24 | 显示全部楼层
转发了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

猜你喜欢
在线客服邮箱
wxcy#wkgb.net

邮箱地址#换为@

Powered by 创意电子 ©2018-现在 专注资源实战分享源码下载站联盟商城