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
    评论
Spring 6中的BeanDefinition是指在Spring容器中定义和配置的一个实例化对象的元数据。它描述了要创建的对象的属性、构造函数参数和其他配置信息。 BeanDefinition包含了以下重要的属性: 1. Bean的Class:指定要创建的对象的类。 2. Bean的作用域(Scope):指定对象的生命周期管理方式,包括Singleton、Prototype、Request、Session等。 3. Bean的依赖关系:指定对象之间的依赖关系,即其他Bean定义的引用。 4. Bean的初始化和销毁方法:指定对象初始化时执行的方法和销毁时执行的方法。 5. Bean的属性值和引用:指定对象的属性值,可以是基本类型值或其他Bean的引用。 6. Bean的构造函数参数:指定实例化对象时传递给构造函数的参数。 通过配置BeanDefinitionSpring容器能够根据这些元数据来创建和管理Bean实例。在容器启动时,会解析并根据BeanDefinition来实例化对象,并进行必要的依赖注入、初始化和销毁操作。每个BeanDefinition都代表了一个独立的对象定义,通过指定不同的属性值和配置,可以创建不同的对象实例。 BeanDefinition的配置可以使用XML、注解或Java Config等方式进行。使用Spring的IoC容器可以很方便地管理和配置大量的BeanDefinition,使得开发人员能够更加灵活和高效地控制对象的创建和管理。 总之,BeanDefinitionSpring框架用于描述和配置对象实例化的元数据,通过配置BeanDefinition,可以对对象的属性、依赖关系、作用域等进行管理和配置,从而实现灵活的对象创建和管理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值