1. Properties of BeanDefinition
BeanDefinition as an interface defines the get and set methods of properties. These attributes are basically defined in its direct implementation class AbstractBeanDefinition. The meaning of each attribute is as shown in the following table:
Type |
Name |
Meaning |
Constant |
SCOPE_DEFAULT |
Default scope: singleton mode |
AUTOWIRE_NO |
no autowiring |
|
AUTOWIRE_BY_NAME |
Autowire by name |
|
AUTOWIRE_BY_TYPE |
Autowire by type |
|
AUTOWIRE_CONSTRUCTOR |
Automatically assemble according to the most matching construction method |
|
AUTOWIRE_AUTODETECT |
Introspect bean classes to determine appropriate autowiring strategies |
|
DEPENDENCY_CHECK_NONE |
No dependency dependency checking |
|
DEPENDENCY_CHECK_OBJECTS |
Dependency checking on object references |
|
DEPENDENCY_CHECK_SIMPLE |
Dependency checking for simple properties |
|
DEPENDENCY_CHECK_ALL |
Dependency checks on all properties |
|
INFER_METHOD |
The container should attempt to infer the destruction method name instead of explicitly specifying the method name |
|
Attribute variables |
beanClass |
Bean’s Class object |
scope |
Scope, default is singleton |
|
abstractFlag |
Whether it is an abstract class tag. The default value is false. If it is true, the bean will not be instantiated. |
|
lazyInit |
Whether to lazy load |
|
autowireMode |
Automatic assembly mode, none by default |
|
dependencyCheck |
Dependency check, default is none |
|
dependsOn |
The names of other beans on which the bean depends |
|
autowireCandidate |
Whether this bean is a candidate for autowiring to other beans, defaults to true |
|
priary |
Whether this bean is the primary autowiring candidate, defaults to false |
|
Qulifiers |
Automatic assembly candidate qualifier map, key: class object name (full class name) |
|
instanceSupplier |
Specify a callback function for creating bean instances as an alternative to declarative factory methods |
|
nonPublicAccessAllowed |
Whether to allow access to non-public constructors and methods, the default is true, and the flag is allowed |
|
lenientConstructorResolution |
Whether to parse the constructor in relaxed mode or strict mode. The default is true, which is relaxed mode. |
|
factoryBeanName |
Factory bean name |
|
factoryMethodName |
Factory method name |
|
constructorArgumentValues |
Constructor parameter values |
|
propertyValues |
attribute value |
|
methodOverrides |
The method that the current bean is overriding |
|
initMethodName |
The name of the initialization method |
|
destroyMethodName |
The name of the method to be destroyed |
|
enforceInitMethod |
Specifies whether the configured method is an initialization method, the default is true |
|
enforceDestroyMethod |
Specifies whether the configured method is a destruction method, the default is true |
|
synthetic |
Whether the beanDefiniton is synthetic, the default is false |
|
role |
Role hint means that the BeanDefinition is the main part of the application. Usually a user-defined bean |
|
description |
beanDefiniton human-readable description |
|
resource |
The resource the beanDefinition comes from |
2. Three subcategories and attributes
AbstractBeanDefinition has three important direct subclasses. In addition to the attributes of the parent class, they also have their own special attributes. First, their class diagram is as follows:
The properties of each of the three direct subclasses are shown in the following table:
Subcategory |
Attribute name |
Attribute meaning |
GenericBeanDefinition |
parentName |
parent bean name |
ChildBeanDefinition |
parentName |
parent bean name |
RootBeanDefinition |
decoratedDefinition |
Recorded beanName, alias, etc. |
qualifiedElement |
Documented annotation elements |
|
stale |
Whether the beanDefinition needs to be re-merged |
|
allowCaching |
Whether to allow caching, default is true |
|
isFactoryMethodUnique |
Whether the factory method is unique, the default is false |
|
resolvedTargetType |
Cache class, indicating which class information RootBeanDefinition stores |
|
isFactoryBean |
Table name whether the bean is a factory bean |
|
factoryMethodReturnType |
Return type of cache factory method |
|
resolvedDestroyMethodName |
Cache resolved destruction method names |
|
resolvedConstructorOrFactoryMethod |
Cache resolved constructor or factory method |
|
constructorArgumentsResolved |
Indicates whether the constructor parameters have been parsed. The default is false. |
|
resolvedConstructorArguments |
Cache resolved constructor parameters |
|
preparedConstructorArguments |
Cache constructor parameters to be parsed |
|
postProcessed |
Whether the table name has been processed by MergedBeanDefinitionPostProcessor, the default is false |
|
beforeInstantiationResolved |
Used when generating a proxy, whether the table name has already generated a proxy |
|
externallyManagedConfigMembers |
Members of the Contractor, Field, and method types are recorded |
|
externallyManagedInitMethods |
The init callback function name in InitializingBean for life cycle callback |
|
externallyManagedDestroyMethods |
The destroy callback function name of DisposableBean for life cycle callback |
3. Applications and differences of the three subcategories
When defining a bean in an XML file, Spring will create a RootBeanDefinition instance, which will save all configuration information, such as class name, attribute values, etc.;
When a bean inherits another bean, Spring will create a ChildBeanDefinition for the child bean and a RootBeanDefinition for the parent bean;
When defining a bean using the @Bean annotation in the configuration class, Spring will create a GenericBeanDefinition instance;
When using annotations (such as @Component, @Service, @Repository, etc.) on a class to define a bean, Spring will create an instance that implements the AnnotatedBeanDefinition interface: AnnotatedGenericBeanDefinition or ScannedGenericBeanDefinition. This instance will save the class name, class type, and all annotation information on the class;
The main differences between GenericBeanDefinition
and AnnotatedBeanDefinition
are as follows:
AnnotatedBeanDefinition
saves the annotation information on the class, but GenericBeanDefinition
does not. This enables Spring
to read and process these annotations at runtime, providing richer functionality.
4. Merger of BeanDefinition
Spring provides a variety of BeanDefinitions, which will eventually be converted or merged into RootBeanDefinition, that is, the configuration information of the child BeanDefinition
and the parent BeanDefinition
Configuration information is combined to form a complete configuration information. The merged BeanDefinition
object contains all the information required for Bean
creation. Spring
will use this complete BeanDefinition
to create Bean
instances.
5. Merge analysis of BeanDefinition
The code is located at: AbstractBeanFactory#getMergedBeanDefinition
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; //The parent bean is empty if (bd.getParentName() == null) { // Use copy of given root bean definition. if (bd instanceof RootBeanDefinition) { // The original BeanDefinition is RootBeanDefinition, cloned directly mbd = ((RootBeanDefinition) bd).cloneBeanDefinition(); } else { //The original BeanDefinition is not RootBeanDefinition, then a new one mbd = new RootBeanDefinition(bd); } } else { //The parent bean is not empty and needs to be merged // Child bean definition: needs to be merged with parent. BeanDefinition pbd; try { String parentBeanName = transformedBeanName(bd.getParentName()); if (!beanName.equals(parentBeanName)) { // Get the RootBeanDefinition corresponding to the parentBeanName in the map 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. // deep copy mbd = new RootBeanDefinition(pbd); // The information related to the BeanDefinition initialized by the child bean overwrites the same information inherited from the RootBeanDefinition. 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 & amp; & amp; !containingBd.isSingleton() & amp; & amp; 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 & amp; & amp; isCacheBeanMetadata()) { this.mergedBeanDefinitions.put(beanName, mbd); } } if (previous != null) { copyRelevantMergedBeanDefinitionCaches(previous, mbd); } returnmbd; } }
The logic flow diagram is as follows:
Summary as follows:
If the bean has no father, generate a new RootBeanDefinition by cloning or deep copying the current beanDefinition and return it;
If the bean has a father, clone or deep copy the parent beanDefinition to generate a new RootBeanDefinition, then overwrite the child beanDefinition property with the same information of the RootBeanDefiniton, and return the RootBeanDefinition.