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中也有提现
接下来梳理下这段代码的实现逻辑
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;
}
}
梳理流程图如下所示: