Spring源码之BeanDefinition合并流程源码解析

Spring的BeanDefinition合并流程

背景

spring通过扫描得到所有的BeanDefination之后,就可以根据BeanDefination创建Bean对象了。在配置文件(spring.xml)中定义如下代码。默认是单例的。

<bean id="child" class="com.xyz.lifeStyle.Child"></bean>

<bean id="parent" class="com.xyz.lifeStyle.Parent"></bean>

MainClass中进行验证是否是单例,即多次获取后是打印的对象地址是否相同

@ComponentScan("com.xyz.lifeStyle")
public class MainClass {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
		Parent parent = context.getBean("parent", Parent.class);
		Parent parent2 = context.getBean("parent", Parent.class);
		System.out.println("打印第一次parent的Scope:"+parent);
		System.out.println("打印第二次parent的Scope:"+parent2);

		Child child = context.getBean("child", Child.class);
		Child child2 = context.getBean("child", Child.class);

		System.out.println("打印第一次child的Scope:"+child);
		System.out.println("打印第二次child2的Scope:"+child2);
	}

}

验证结果如下:打印出的类都是相同的bean
在这里插入图片描述
接下来将配置文件的bean设置改为如下配置在运行看结果

<bean id="child" class="com.xyz.lifeStyle.Child" parent="parent"></bean>
	
<bean id="parent" class="com.xyz.lifeStyle.Parent" scope="prototype"></bean>

在这里插入图片描述
打印的结果是两个bean都变为了多例。这是为什么呢?是由于子类将父类的属性进行继承下来了。当然如果子类定义了对应的属性那么会对父类的属性进行覆盖。

合并BeanDefinition

在spring进行创建bean之前会将bean定义进行合并为RootBeanDefinition。在spring的DefaultListableBeanFactory中也有提现
在这里插入图片描述在这里插入图片描述

接下来梳理下这段代码的实现逻辑
AbstractBeanFactory.java中

protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
			throws BeanDefinitionStoreException {
		//全局加锁
		synchronized (this.mergedBeanDefinitions) {
			RootBeanDefinition mbd = null;
			if (containingBd == null) {
				mbd = this.mergedBeanDefinitions.get(beanName);
			}
			if (mbd == null) {
				// bd.getParentName() == null,表明无父配置,这时直接将当前的 BeanDefinition 升级为 RootBeanDefinition
				if (bd.getParentName() == null) {
					//直接把原始的bean定义升级为RootBeanDefinition
					if (bd instanceof RootBeanDefinition) {
						mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
					}
					else {
						//包裹为RootBeanDefinition
						mbd = new RootBeanDefinition(bd);
					}
				}
				//有父定义
				else {
					BeanDefinition pbd;
					try {
						String parentBeanName = transformedBeanName(bd.getParentName());
						if (!beanName.equals(parentBeanName)) {
							//递归
							pbd = getMergedBeanDefinition(parentBeanName);
						}
						else {
							/*
							 * 这里再次调用 getMergedBeanDefinition,只不过参数值变为了
							 * parentBeanName,用于合并父 BeanDefinition 和爷爷辈的
							 * BeanDefinition。如果爷爷辈的 BeanDefinition 仍有父
							 * BeanDefinition,则继续合并
							 */
							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 an AbstractBeanFactory parent");
							}
						}
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
								"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
					}
					// 以父 BeanDefinition 的配置信息为蓝本创建 RootBeanDefinition,也就是“已合并的 BeanDefinition”
					mbd = new RootBeanDefinition(pbd);
					// 用子 BeanDefinition 中的属性覆盖父 BeanDefinition 中的属性
					mbd.overrideFrom(bd);
				}

				// 如果用户未配置 scope 属性,则默认将该属性配置为 singleton
				if (!StringUtils.hasLength(mbd.getScope())) {
					mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
				}

				if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
					mbd.setScope(containingBd.getScope());
				}

				//缓存合并后的 BeanDefinition
				if (containingBd == null && isCacheBeanMetadata()) {
					this.mergedBeanDefinitions.put(beanName, mbd);
				}
			}

			return mbd;
		}
	}

梳理流程图如下所示:在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值