Full analysis of Beanefinition in spring

Everyone who has used spring should know that BeanDefinition records the definition information of beans, but when we look at the source code, we will find that there are many classes derived from the BeanDefinition interface in the source code, such as GenericBeanDefinition, AnnotatedGenericBeanDefinition, RootBeanDefinition, etc., so what is there between them The difference, under what circumstances are they used? This article will take everyone to discuss.

1, BeanDefinition commonly used class diagram

Insert picture description here

2. BeanDefinition interface

BeanDefinition is an interface that defines the modification and acquisition of Bean attribute values ​​and metadata information. BeanDefinitionMap is defined in DefaultListableBeanFactory to record the parsed BeanDefinition, and beanDefinitionNames is defined to record the list of BeanDefinition names:

/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/** List of bean definition names, in registration order. */
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

3,AbstractBeanDefinition

		new AbstractBeanDefinition() {
    
    
            @Override
            public void setParentName(String parentName) {
    
    

            }

            @Override
            public String getParentName() {
    
    
                return null;
            }

            @Override
            public AbstractBeanDefinition cloneBeanDefinition() {
    
    
                return null;
            }
        };

AbstractBeanDefinition is an abstract implementation of the BeanDefinition interface, except for the above three methods in BeanDefinition which are not implemented, all the rest are implemented.

4,GenericBeanDefinition

The GenericBeanDefinition class is a concrete realization of the AbstractBeanDefinition class, meaning a generic BeanDefinition.

Generally, ordinary beans defined by xml will be parsed as GenericBeanDefinition in the source code.

The following xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="a" class="com.mashibing.A"></bean>
</beans>

Debug information

Insert picture description here

5,RootBeanDefinition

RootBeanDefinition is also one of the implementation classes of AbstractBeanDefinition. It can be used as a BeanDefinition alone or as a parent class of other BeanDefinitions. RootBeanDefinition defines more attributes on the basis of AbstractBeanDefinition.

The invokeBeanFactoryPostProcessors(beanFactory) in the refresh method of the spring source code to execute all the BeanFactoryPostProcessor will traverse the beanDefinitionNames collection, and then merge all the BeanDefinitions in the beanDefinitionMap into RootBeanDefinitions and cache them in the mergedBeanDefinitions, so that when the bean is instantiated, pass getMergedLocalBeanDefinition can be taken out directly from mergedBeanDefinitions.

/** Map from bean name to merged RootBeanDefinition. */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

Insert picture description here

protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
			throws BeanDefinitionStoreException {
    
    

		synchronized (this.mergedBeanDefinitions) {
    
    
			// 用于存储bd的MergedBeanDefinition
			RootBeanDefinition mbd = null;
			RootBeanDefinition previous = null;

			// Check with full lock now in order to enforce the same merged instance.
			// 检查beanName对应的MergedBeanDefinition是否存在于缓存中
			if (containingBd == null) {
    
    
				mbd = this.mergedBeanDefinitions.get(beanName);
			}

			// 如果缓存中没有
			if (mbd == null || mbd.stale) {
    
    
				previous = mbd;
				// 如果bd的parentName为空,代表bd没有父定义,无需与父定义进行合并操作
				if (bd.getParentName() == null) {
    
    
					// Use copy of given root bean definition.
					// 如果bd的类型为RootBeanDefinition,则bd的MergedBeanDefinition就是bd本身,则直接克隆一个副本
					if (bd instanceof RootBeanDefinition) {
    
    
						mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
					}
					else {
    
    
						// 否则,将bd作为参数,构建一个RootBeanDefinition。
						// 正常使用下,BeanDefinition在被加载后是GenericBeanDefinition或ScannedGenericBeanDefinition
						mbd = new RootBeanDefinition(bd);
					}
				}
				else {
    
    
					// Child bean definition: needs to be merged with parent.
					// bd存在父定义,需要与父定义合并
					BeanDefinition pbd;
					try {
    
    
						// 获取父bean的名称,并进行转换
						String parentBeanName = transformedBeanName(bd.getParentName());
						// 如果当前beanName和父beanName不相同,那么递归调用合并方法
						if (!beanName.equals(parentBeanName)) {
    
    
							pbd = getMergedBeanDefinition(parentBeanName);
						}
						// 如果父定义的beanName与bd的beanName相同,则拿到父BeanFactory,
						// 只有在存在父BeanFactory的情况下,才允许父定义beanName与自己相同,否则就是将自己设置为父定义
						else {
    
    
							BeanFactory parent = getParentBeanFactory();
							// 如果父BeanFactory是ConfigurableBeanFactory,则通过父BeanFactory获取父定义的MergedBeanDefinition
							if (parent instanceof ConfigurableBeanFactory) {
    
    
								pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
							}
							else {
    
    
								// 如果父BeanFactory不是ConfigurableBeanFactory,则抛异常
								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 p标注 @Bean 注解的类会使用构造方法自动装配

arent bean definition '" + bd.getParentName() + "'", ex);
					}
					// Deep copy with overridden values.
					// 使用父定义pbd构建一个新的RootBeanDefinition对象
					mbd = new RootBeanDefinition(pbd);
					// 使用bd覆盖父定义
					mbd.overrideFrom(bd);
				}

				// Set default singleton scope, if not configured before.
				// 如果没有指定scope,那么设置默认的scope为单例
				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.
				// 如果containingBd不为空 && containingBd不为singleton && mbd为singleton,则将mdb的scope设置为containingBd的scope
				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)
				// 将beanName与mbd放到mergedBeanDefinitions缓存,以便之后可以直接使用
				if (containingBd == null && isCacheBeanMetadata()) {
    
    
					this.mergedBeanDefinitions.put(beanName, mbd);
				}
			}
			if (previous != null) {
    
    
				copyRelevantMergedBeanDefinitionCaches(previous, mbd);
			}
			// 返回MergedBeanDefinition
			return mbd;
		}
	}

When instantiating the Bean, take the RootBeanDefinition directly from the mergedBeanDefinitions cache

6,ChildBeanDefinition

ChildBeanDefinition inherits from AbstractBeanDefinition. It is equivalent to a subclass and cannot exist alone. It must rely on a parent BeanDetintion. When constructing a ChildBeanDefinition, pass in the name of the parent BeanDetintion through the constructor or set the parent name through setParentName. It can inherit method parameters and attribute values ​​from the parent class, and can override the methods of the parent class, and it can also add new properties or methods.

Starting from Spring 2.5, the preferred method for registering Bean definitions programmatically is GenericBeanDefinition. GenericBeanDefinition can effectively replace ChildBeanDefinition in most sub-use occasions.

7,AnnotatedBeanDefinition

AnnotatedBeanDefinition is one of the BeanDefinition sub-interfaces, which extends the functions of BeanDefinition and is used to manipulate annotation metadata. Under normal circumstances, the Bean (@Component, @Bean) obtained through annotation, the BeanDefinition type is the implementation class of the interface.

public interface AnnotatedBeanDefinition extends BeanDefinition {
    
    

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

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

This interface can return two metadata classes:

  • AnnotationMetadata: Mainly operate on the annotation information of the Bean, such as obtaining all annotations marked by the current Bean, and judging whether the specified annotations are included.
  • MethodMetadata: The metadata class of the method. Provide the name of the acquisition method, the full class name of the class to which this method belongs, whether it is an abstract method, whether it is a static method, whether it is a final method, etc.

8,ScannedGenericBeanDefinition

ScannedGenericBeanDefinition inherits from GenericBeanDefinition and implements the AnnotatedBeanDefinition interface. This BeanDefinition is used to describe the Bean annotated with @Component, and its derivative annotations such as @Service and @Controller are the same.

In the source code, the xml configuration file is parsed during loadBeanDefinition. If the component-scan tag is included, the package specified by the base-package of the component-scan is scanned for classes that contain @Component annotations (including @Service, @Controller), and add Into the beanDefinitionMap.
Insert picture description here

9,AnnotatedGenericBeanDefinition

AnnotatedGenericBeanDefinition inherits from GenericBeanDefinition and implements the AnnotatedBeanDefinition interface. This BeanDefinition is used to describe the bean injected through the @Import annotation.

10,ConfigurationClassBeanDefinition

ConfigurationClassBeanDefinition inherits from RootBeanDefinition and implements the AnnotatedBeanDefinition interface. This BeanDefinition is used to describe the bean instantiated by @Bean annotation in the class annotated with @Configuration annotation.
Its features are as follows:

  • If the @Bean annotation does not specify the name of the bean, the bean will be named by the method name by default.
  • The class annotated with @Configuration will become a factory class, and the method annotated with @Bean will become a factory method. The Bean is instantiated through the factory method instead of directly initialized by the constructor.
  • The class annotated with @Bean will be automatically assembled using the constructor.

Guess you like

Origin blog.csdn.net/u013277209/article/details/109487922