During Spring IOC source analysis, there is a class called BeanDefinition that comes up repeatedly. In Spring, there are many ways to source beans, such as using XML configuration, @configration configuration, @bean primary key, etc. Different beans have different dependencies. Spring provides beanDefinitions to do this.

The definition of a Bean is mainly described by a BeanDefinition. As the data structure used to wrap beans in Spring, let’s take a look under the veil.

BeanDefinition definition

The first is the definition of BeanDefinition:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement
Copy the code

As can be seen from the comments given in the source code, BeanDefinition, as the interface to define beans in Spring, can be said to be the abstract data structure of beans, including property parameters, constructor parameters, and further information about the concrete implementation.

BeanDefinition structure

Let’s take a look at BeanDefinition’s inheritance structure as follows:

The most striking thing about BeanDefinition’s inheritance structure is that the whole inheritance relationship has clear responsibilities and is layered on top of each other. If you look closely at Spring’s source code, you’ll see such designs everywhere.

A BeanDefinition describes an instance of a Bean, including property values, constructor parameter values, and more information about the classes that inherit from it. For the design of the top-level interface BeanDefinition, Spring developers designed a unified abstract model by analyzing and modeling the behavior and functions required by the Bean definition description. Those of you who are familiar with DDD will notice that this is the result of domain analysis modeling. Spring source code in the face of abstract interface design is more perfect and have reference value, there are a lot of places worth learning. We can analyze and think about some of these designs while reading Spring source code, and then summarize our own methods and accumulate experience.

The AbstractBeanDefinition abstract class provides a unified implementation of some methods of the BeanDefinition interface. The following subclasses are classes that actually have business meaning, such as RootBeanDefinition, ChildBeanDefinition, etc., which implement or redefine some of their behaviors according to specific business requirements (of course, the whole process is carried out within the domain boundaries of BeanDefinition). Each of these classes will be parsed in the following sections.

First, it can be seen from the class diagram that BeanDefinition inherits AttributeAccessor and BeanMetadataElement. The principle of interface isolation, by the way, is used here, and you can see it everywhere in Spring, as an effort to better implement a single responsibility.

AttributeAccessor

It is primarily used to define a generic interface for attaching and accessing metadata

// Define a generic interface for attaching and accessing metadata, Public interface AttributeAccessor {// Set the value of the attribute void setAttribute(String name, @nullable Object value); Nullable Object getAttribute(String name); // Get the value of the specified attribute name. @nullable Object removeAttribute(String name); Boolean hasAttribute(String name); // Check whether the specified attribute name exists. // Get the name of all attributes String[] attributeNames(); }Copy the code

BeanMetadataElement

Metadata, returns the Bean’s origin, and BeanMetadataElement has only one method that returns the object of the configurable source.

This method is often used in @Configuration because it is proxyed

Public interface BeanMetadataElement {@nullable default Object getSource() {return null; }}Copy the code

Based on the introduction of AttributeAccessor and BeanMetadataElement, it can be seen that BeanDefinition realizes these two interfaces have corresponding behaviors and attributes, mainly for the storage of attributes and parameters and related source objects.

BeanDefinition source

The interfaces to AttributeAccessor and BeanMetadataElement are described as a single responsibility. BeanDefinition is just one of the most simple interface, the main function is to allow the spring BeanFactoryPostProcessor, such as PropertyPlaceHolderConfigure to retrieve and modify the attribute values and other Bean metadata, Let’s take a look at what BeanDefinition’s source code actually contains. (Spring’s notes are more detailed, and some notes have been deleted for the length of the article.)

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {/ / said the scope of the bean is a singleton or archetypal pattern String SCOPE_SINGLETON = ConfigurableBeanFactory. SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; /** * the role of the bean */ // default, for the application defined int ROLE_APPLICATION = 0; Int ROLE_SUPPORT = 1; // As part of the extensive configuration (support, extended classes), what it really means is that my Bean belongs to the user and comes from the configuration file. Int ROLE_INFRASTRUCTURE = 2; ROLE_INFRASTRUCTURE = 2; ROLE_INFRASTRUCTURE = 2; // Modifiable Attributes // void setParentName(@nullable String parentName); @Nullable String getParentName(); // Specify the name of the bean class defined by this bean. The class name can be changed during the bean factory's later processing, usually replacing the original class name with the parsed class name. void setBeanClassName(@Nullable String beanClassName); @Nullable String getBeanClassName(); SCOPE_SINGLETON or SCOPE_PROTOTYPE void setScope(@nullable String scope); @Nullable String getScope(); Void setLazyInit(Boolean lazyInit); void setLazyInit(Boolean lazyInit); boolean isLazyInit(); /** * dependsOn usually applies when there is no dependency between two beans, but the latter bean needs the result of the initial method executed by the former bean. If < bean id= "a" dependsOn= "b" /> * < bean ID = "a" dependsOn= "b" /> */ void setDependsOn(@Nullable String... dependsOn); @Nullable String[] getDependsOn(); // Note: this flag only affects assembly by type, not byName injection // no: autowire is not used, dependencies must be specified through the ref element, which is the default. // byName: Automatic assembly with the property name. If there is one bean of the same type as the specified property name, the assembly is automatic. If there are more than one bean, an exception is thrown. // byType: automatic state byType. If there are beans of the same type as the specified property, the assembly is automatic. If there are more than one, an exception is thrown. Constructor: Similar to byType except that it uses the type of the constructor argument. // Autodetect: The bean's introspection mechanism determines whether to use constructor or byType for auto-assembly. Use byType if there is a default // constructor, constructor otherwise. void setAutowireCandidate(boolean autowireCandidate); boolean isAutowireCandidate(); If the primary attribute of the bean is true, then the bean will take precedence over the one whose primary is true. If there are more than one true primary, then an exception will be thrown. // @Primary void setPrimary(boolean primary); boolean isPrimary(); Void setFactoryBeanName(@nullable String factoryBeanName); @Nullable String getFactoryBeanName(); // Specify factory method ~ void setFactoryMethodName(@nullable String factoryMethodName); @Nullable String getFactoryMethodName(); / / return the bean constructor parameters ConstructorArgumentValues getConstructorArgumentValues (); default boolean hasConstructorArgumentValues() { return ! getConstructorArgumentValues().isEmpty(); } // Property set 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. * @destroyMethodName */ void setDestroyMethodName(@destrolable String destroyMethodName);  /** * Return the name of the destroy method. * @destroyMethodName (); Void setRole(int role); int getRole(); // @Description void setDescription(@Nullable String description); @Nullable String getDescription(); // Read-only attributes ResolvableType getResolvableType(); boolean isSingleton(); boolean isPrototype(); Boolean isAbstract(); 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(); // Return the original BeanDefinition, If there is no return @ null / / if this Bean definition is agent, this method can be modified to return to the original @ Nullable BeanDefinition getOriginatingBeanDefinition (); }Copy the code

Here you can take a closer look at the design of BeanDefinition and how Spring describes beans through an object called BeanDefinition. The later stage is to describe the object to determine how to instantiate the Bean object. In fact, think about how we would design such a class, how Spring would design it, and what the gap is.

Of course this whole process corresponds exactly to the relevant configuration properties in this, or the relevant annotations in the @bean.

AbstractBeanDefinition source

Considering the large amount of the whole source code, here separately show the analysis

Public static final String SCOPE_DEFAULT = ""; / / automatic assembly of some constants public static final ints 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;Copy the code

SCOPE_DEFAULT Sets the Scope of the default Bean, In the corresponding BeanDefinition ConfigurableBeanFactory. SCOPE_SINGLETON and ConfigurableBeanFactory. SCOPE_PROTOTYPE

Set the auto-assembly constants:

  • No: No autowire is not used. Dependencies must be specified through the ref element, the default for autowire.

  • ByName: Automatic assembly with the property name, if there is one bean of the same type as the specified property name, and if there are more than one, an exception is thrown.

  • ByType: automatic state byType. If there are beans of the same type as the specified property, the assembly is automatic, and if there are more than one, an exception is thrown.

  • Constructor: Similar to byType except that it uses the type of the constructor argument.

  • Autodetect: The bean’s introspection mechanism determines whether to use constructor or byType for auto-assembly. Use byType if there is a default constructor, constructor otherwise.

    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;Copy the code

Checking dependencies on demand can be implemented in different ways according to different configurations. The corresponding parsing is shown in the code comment above.

/** * 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 the bean does not specify a destruction method, the container should try to infer the name of the bean's destruction method. For now, The inferred destruction method is usually named close or shutdown * (that is, no Bean destruction method is specified, but a method named close or shutdown is defined internally, Public static final String INFER_METHOD = "(inferred)"; @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; // The autowire-candidate property is set to false so that the container does not consider the bean when looking for autowier-candidate, // Note: Private Boolean autowireCandidate = true; Private Boolean primary = false; // The only way to place a value on this field is in this class: Public void addQualifier (AutowireCandidateQualifier qualifier) copyQualifiersFrom this doesn't count, that belongs to copy / / call: AnnotatedBeanDefinitionReader# doRegisterBean but Spring all calls, the qualifiers field travels are null ~ ~ ~ ~ ~ ~ ~ ~ ~ embarrassed / / how I put tracking found that This field will never be assigned at this time (unless we manually call the corresponding method to assign it), but it is possible that I am not knowledgeable, please let me know if I know, thank you very much. Considering that it may be a reserved field ~~~~ // I initially thought this would be the way to assign: @qualifier ("aaa") // @qualifier ("aaa") // @qualifier ("aaa") // @service //public class HelloServiceImpl There are no values in Bean definitions, so the corresponding methods getQualifier and getQualifiers should basically return null or [] private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(); // The only way to place a value on this field is in this class: Public void addQualifier (AutowireCandidateQualifier qualifier) copyQualifiersFrom this doesn't count, that belongs to copy / / call: AnnotatedBeanDefinitionReader# doRegisterBean but Spring all calls, the qualifiers field travels are null ~ ~ ~ ~ ~ ~ ~ ~ ~ embarrassed / / how I put tracking found that This field will never be assigned at this time (unless we manually call the corresponding method to assign it), but it is possible that I am not knowledgeable, please let me know if I know, thank you very much. Considering that it may be a reserved field ~~~~ // I initially thought this would be the way to assign: @qualifier ("aaa") // @qualifier ("aaa") // @qualifier ("aaa") // @service //public class HelloServiceImpl There are no values in Bean definitions, so the corresponding methods getQualifier and getQualifiers should basically return null or [] private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0); Nullable private Supplier<? Nullable private Supplier<? > instanceSupplier; Private Boolean nonPublicAccessAllowed = true; private Boolean nonPublicAccessAllowed = true; private Boolean nonPublicAccessAllowed = true; In a loose pattern in the / / parsing constructor, the default is true (loose and strict embodies in type matching) private Boolean lenientConstructorResolution = true; // Factory-method @nullable private String factoryBeanName; // factoryMethodName @nullable private String factoryMethodName; / / record constructor injection properties, the corresponding bean property constructor - arg @ Nullable private ConstructorArgumentValues ConstructorArgumentValues; @nullable private MutablePropertyValues propertyValues; @nullable private MutablePropertyValues propertyValues; @nullable private MethodOverrides MethodOverrides; private MethodOverrides MethodOverrides; @nullable private String initMethodName; @nullable private String destroyMethodName; // Whether init-method is enforceable, the program is set to private Boolean enforceInitMethod = true; private boolean enforceDestroyMethod = true; Private Boolean synthetic = false; // Synthetic = false; // Synthetic = false; Private int role = BeanDefinition.ROLE_APPLICATION; @nullable private String description; // The resource that this bean definition came from @nullable private resource resource;Copy the code
  • MutablePropertyValues: This class holds the bean-related property values, which are the values of the GET /set methods.

When I look at the objects here they fall into two main categories,

  1. Is a description of some configuration of the Bean, such as how to create the Bean, or whether the Bean has certain features;
  2. MutablePropertyValues is the definition of the Bean’s own property values

I feel that Spring’s design is still more in line with the idea of class composition, combining classes of different functions with each other to complete a detailed description of a Bean, so to say from creation – “initialization -” destruction. Configuration and description of beans throughout their life cycle in Spring.

The basic attribute values of AbstractBeanDefinition above are summarized and annotated, and relevant materials are also referred to. AbstractBeanDefinition defines the properties of a Bean description from the source code, and you can see the default configuration for the properties of a Bean description.

AbstractBeanDefinition abstract class mainly implements a set of generic attribute descriptions for the BeanDefinition interface. For specific subclasses such as

GenericBeanDefinition,

RootBeanDefinition,

ChildBeanDefinition

Implementation provides more convenience by extracting common parts into abstract classes. This is probably one of the more common scenarios for abstract classes. Of course, the specific advantages and disadvantages of abstract classes and interfaces are not detailed here.

So let’s look at the implementation classes that are derived, so let’s look at them first

GenericBeanDefinition,

RootBeanDefinition,

ChildBeanDefinition.

They’re both directly implementing AbstractBeanDefinition.

GenericBeanDefinition

GenericBeanDefinition

Parent BeanDefinition is an implementation class of the standard BeanDefinition, and like any other Bean definition, can be set to parent BeanDefinition by setting “parentName” in addition to optional constructor parameter values and attribute values. The source code is as follows:

@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(); }}Copy the code

The source code for GenericBeanDefinition is relatively simple, just adding a parentName property value. The rest of the implementation is in AbstractBeanDefinition. Beans configured in XML are added as GenericBeanDefinition types. The following

// BeanDefinitionParserDelegate.java public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @nullable BeanDefinition containingBean) {// 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; }Copy the code

BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, String beanName, The @Nullable BeanDefinition containingBean method has this line of code. (about BeanDefinitionParserDelegate behind spring BeanDefinition registration will be detailed explanation)

AbstractBeanDefinition bd = createBeanDefinition(className, parent); AbstractBeanDefinition bd = createBeanDefinition(className, parent);Copy the code

Let’s take a look at this line of code createBeanDefinition, so let’s trace it in

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

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

We can see BeanDefinitionReaderUtils this utility class, mainly through his specific BeanDefinition object to create

//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; }Copy the code

Here you can basically see that beans configured in XML are initially parsed to GenericBeanDefinition.

GenericBeanDefinition parentName (parentName) GenericBeanDefinition parentName (parentName) There are two main requirements for this parent:

  1. The child Bean must be compatible with the parent Bean, that is, it must have all the attributes defined by the parent Bean
  2. The parent Bean must either be abstract or have lazy-init=true defined so that the Bean factory does not instantiate the Bean

ChildBeanDefinition

ChildBeanDefinition inherits the definition of the Bean set by the parent class, with fixed dependencies on the parent Bean definition (RootBeanDefinition). It inherits the constructor’s arguments, attribute values, and overridden methods and options from the parent Bean to add new values.

Note: Since Spring 2.5, the preferred method definition for registering beans is the GenericBeanDefinition class, which allows dynamic definition of parent dependencies GenericBeanDefinition#setParentName, This effectively replaces the ChildBeanDefinition class in most use cases.

public class ChildBeanDefinition extends AbstractBeanDefinition {

    @Nullable
    private String parentName;
Copy the code

As you can see from the source code, ChildBeanDefinition is basically similar to GenericBeanDefinition. According to the comments in the source code, it is basically recommended to use GenericBeanDefinition instead of ChildBeanDefinition.

RootBeanDefinition

Define a mergable Bean definition that returns a specific Bean during the Spring BeanFactory run. It may be created from multiple original bean definitions that inherit from each other, and GenericBeanDefinition is often recommended.

Public class RootBeanDefinition extends AbstractBeanDefinition {public class RootBeanDefinition extends AbstractBeanDefinition { BeanDefinition @Nullable private BeanDefinitionHolder decoratedDefinition; @nullable private AnnotatedElement qualifiedElement; // Determine whether /** Determines if the definition needs to be merged. */ Volatile Boolean stale; // allowCaching for Boolean allowCaching = true; Boolean isFactoryMethodUnique; // reflect @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; . Omit some code}Copy the code

Abstractbeandefiniiton: RootBeanDefiniiton: RootBeanDefiniiton: RootBeanDefiniiton: RootBeanDefiniiton: RootBeanDefiniiton

  1. BeanDefinitionHolder defines the correspondence between ID, alias, and Bean
  2. AnnotatedElement of a Bean
  3. The concrete factory Method (Class type), including the return type of the factory Method, and the Method object of the factory Method
  4. Constructor, constructor parameter type
  5. The class object of the Bean

It can be seen that RootBeanDefinition and AbstractBeanDefinition are complementary. RootBeanDefinition defines more attributes based on AbstractBeanDefi**** Nition. The information needed to initialize the Bean is basically complete

RootBeanDefiniiton **getMergedBeanDefinition ** Spring has a very important code for RootBeanDefiniiton:

RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
Copy the code

Those of you who read the source code carefully will have seen similar code in Spring. So what does this line of code do? Let’s look at it in detail.

MergedBeanDefinition generated

Let’s take a look at AbstractBeanFactory# getMergedLocalBeanDefinition code has this as the breakthrough point, analysis the MergedBeanDefinition generation process

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)); }Copy the code

The above code first tries to get the RootBeanDefinition from the cache, if not generated by the getMergedBeanDefinition(beanName, getBeanDefinition(beanName)) method. You can actually see the core code here, so let’s track it down.

protected RootBeanDefinition getMergedBeanDefinition( String beanName, BeanDefinition bd, @ Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException {/ / lock to prevent synchronized concurrency problems (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; // There are two main types of BD when there is no PARENtname // 1 A separate GenericBeanDefinition // 2. A RootBeanDefinition if (bd.getParentName() == null) {// Use copy of given root bean definition 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()); Because BD has parent, and its parent may also have prent, we need to use recursive 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; }}Copy the code

As you can see from the code above, this process is done by recursively using getMergedBeanDefinition(), placing parent in the middle PBD, and finally by MBD = new RootBeanDefinition(PBD); Set the parent property and related parameters to a final RootBeanDefinition. The main things to do are the following steps:

  • Check whether a BeanDefinition has a parentName. If not, it may be a GenericBeanDefinition or RootBeanDefinition. Just return the BeanDefinition
  • If parentName is present, return RootBeanDefinition recursively and passnew RootBeanDefinition(pbd);Merge the parent and child BeanDefinitions to return a new RootBeanDefinition

Let’s take a look at the constructor of RootBeanDefinition(BeanDefinition Original) and see if it can actually merge the original property and the parameter.

    RootBeanDefinition(BeanDefinition original) {
        super(original);
    }
Copy the code

Let’s take a look at the constructor of the AbstractBeanDefinition superclass

// 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()); }}Copy the code

At this point, it’s almost certain that the constructor simply makes a deep copy of the given BeanDefinition argument, generating a new BeanDefinition object. This fully validates our analysis of the generation process of ****MergedBeanDefinition.