05、Spring源码分析:spring中Beanefinition完全解析

大家用过spring的应该都知道BeanDefinition是记录bean的定义信息的,但是我们看源码时会发现,源码中通过BeanDefinition接口派生出来好多类,比如GenericBeanDefinition,AnnotatedGenericBeanDefinition,RootBeanDefinition等等,那么他们之间有什么区别,都是在什么情况下用到的呢?这篇文章就带大家一起探讨。

1,BeanDefinition常用类关系图

*

2,BeanDefinition接口

BeanDefinition是一个接口,定义了修改和获取Bean属性值和元数据信息。在DefaultListableBeanFactory中定义了BeanDefinitionMap来记录解析的BeanDefinition,定义了beanDefinitionNames来记录BeanDefinition名字列表:

/** 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是BeanDefinition接口的抽象实现,除了BeanDefinition中的以上三个方法没实现,其余的全部实现了。

4,GenericBeanDefinition

GenericBeanDefinition类是AbstractBeanDefinition类的具体实现,义为通用的BeanDefinition。

一般我们通过xml定义的普通bean在源码中会被解析为GenericBeanDefinition。

如下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>

调试信息

*

5,RootBeanDefinition

RootBeanDefinition也是AbstractBeanDefinition的其中一个实现类,它可以单独作为一个BeanDefinition,也可以作为其他 BeanDefinition 的父类。RootBeanDefinition 在 AbstractBeanDefinition 的基础上定义了更多属性。

在spring源码的refresh方法中的invokeBeanFactoryPostProcessors(beanFactory)去执行所有的BeanFactoryPostProcessor时会通过去遍历beanDefinitionNames集合,然后把beanDefinitionMap中的BeanDefinition全部合并为RootBeanDefinition,并且缓存到mergedBeanDefinitions中,这样在实例化bean时,通过getMergedLocalBeanDefinition直接从mergedBeanDefinitions中取出来即可。

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

*

*

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;
		}
	}

*

6,ChildBeanDefinition

ChildBeanDefinition继承自 AbstractBeanDefinition。其相当于一个子类,不可以单独存在,必须依赖一个父 BeanDetintion,构造 ChildBeanDefinition 时,通过构造方法传入父 BeanDetintion 的名称或通过 setParentName 设置父名称。它可以从父类继承方法参数、属性值,并可以重写父类的方法,同时也可以增加新的属性或者方法。

从Spring 2.5 开始,以编程方式注册 Bean 定义的首选方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的绝大分部使用场合。

7,AnnotatedBeanDefinition

AnnotatedBeanDefinition 是 BeanDefinition 子接口之一,该接口扩展了 BeanDefinition 的功能,其用来操作注解元数据。一般情况下,通过注解方式得到的 Bean(@Component、@Bean),其 BeanDefinition 类型都是该接口的实现类。

public interface AnnotatedBeanDefinition extends BeanDefinition {
   
     

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

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

该接口可以返回两个元数据的类:

  • AnnotationMetadata:主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。
  • MethodMetadata:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。

8,ScannedGenericBeanDefinition

ScannedGenericBeanDefinition继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述标注 @Component 注解的 Bean,其派生注解如 @Service、@Controller 也同理。

其在源码中是在loadBeanDefinition时解析xml配置文件,如果包含component-scan标签,就扫描component-scan的base-package指定的包下包含@Component注解(当然包括@Service,@Controller)的类,添加的beanDefinitionMap中注入进来。
*

9,AnnotatedGenericBeanDefinition

AnnotatedGenericBeanDefinition继承自 GenericBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述通过@Import注解方式注入的 Bean。

10,ConfigurationClassBeanDefinition

ConfigurationClassBeanDefinition继承自 RootBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个 BeanDefinition 用来描述在标注 @Configuration 注解的类中,通过 @Bean 注解实例化的 Bean。
其功能特点如下:

  • 如果 @Bean 注解没有指定 Bean 的名字,默认会用方法的名字命名 Bean。
  • 标注 @Configuration 注解的类会成为一个工厂类,而标注 @Bean 注解的方法会成为工厂方法,通过工厂方法实例化 Bean,而不是直接通过构造方法初始化。
  • 标注 @Bean 注解的类会使用构造方法自动装配。