Spring源码系列(十六)Spring合并BeanDefinition的原理

1.写在前面

前面的博客,笔者介绍spring中创建Bean的过程,但是还是没有讲完,只讲了如何将这个Bean给实例化出来,但是有关这个bean的所有的内容、属性等等东西,都还没有填充,由于将后面的创建的Bean的流程,需要了解合并BeanDefinition的原理,所以今天笔者打算讲下合并BeanDefinition的原理讲下。

2.什么是合并BeanDefinition

我们先来看个例子,具体的代码如下:

package com.ys.mergeBeanDefinition;

public class RootBean {
    private String name;
    private String age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "RootBean{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

package com.ys.mergeBeanDefinition;

public class ChildBean {
    private String name;
    private String age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "ChildBean{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

package com.ys.mergeBeanDefinition;

import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        RootBeanDefinition rootBean = new RootBeanDefinition();
        rootBean.setBeanClass(RootBean.class);
        rootBean.getPropertyValues().add("name","张三");
        rootBean.getPropertyValues().add("age","18");
        context.registerBeanDefinition("root", rootBean);

        GenericBeanDefinition childBean = new GenericBeanDefinition();
        childBean.setBeanClass(ChildBean.class);
        childBean.getPropertyValues().add("name", "李四");
        childBean.setParentName("root");
        context.registerBeanDefinition("child", childBean);
        context.refresh();

        System.out.println(context.getBean(ChildBean.class));

    }
}

运行的结果如下:

在这里插入图片描述

可以看到笔者没有给childBean设置age的属性,但是这儿打印age的是18,笔者只在这儿设置了一个parentName属性,spring就帮我们进行合并了,所以我们在创建Bean的时候,实际上用来创建的Bean的BeanDefinition都是经过Spring进行合并后的BeanDefinition,因为这儿如果创建ChildBean采用的它没有合并过的BeanDefinition的话,这儿创建出来的ChildBean中age的属性应该是空的。

3.如何合并BeanDefinition

那么在什么时候合并BeanDefinition呢?合并BeanDefinition肯定在创建Bean之前,而且创建BeanDefinition之前,一定要看这个parentName的值是不是空,如果是空就不合并,如果不是空就合并。于是笔者在GenericBeanDefinitiongetParentName的方法加了一个断点,然后调试这个方法,看对应的调用栈如下:

在这里插入图片描述

可以看到我们第一次的合并在调用getBeanNamesForType的方法的时候,就开始合并了。然后调用的是doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);在这个方法中调用了getMergedLocalBeanDefinition(beanName);进行对应的合并。于是笔者就直接看这部分的代码,具体的代码如下:

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
	// Quick check on the concurrent map first, with minimal locking.
	RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
	if (mbd != null && !mbd.stale) {
		return mbd;
	}
	return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

于是笔者在这儿加了一个条件断点,先查看一下rootBean的情况,再查看childBean的情况,第一次从mergedBeanDefinitions这个变量中取值,肯定是没有值,只有合并过后,这个mergedBeanDefinitions中才有值,于是会调用getMergedBeanDefinition(beanName, getBeanDefinition(beanName));方法,具体的代码如下:

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

	return getMergedBeanDefinition(beanName, bd, null);
}

发现继续调用的是getMergedBeanDefinition(beanName, bd, null);的方法,具体的代码如下:

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

	synchronized (this.mergedBeanDefinitions) {
		RootBeanDefinition mbd = null;
		RootBeanDefinition previous = null;

		// Check with full lock now in order to enforce the same merged instance.
        // 第一次这个值为空
		if (containingBd == null) {
            //这个取出来的值也是空,因为没有合并过
			mbd = this.mergedBeanDefinitions.get(beanName);
		}

        //上面取出来的值为空,所以这儿会进入这个判断
		if (mbd == null || mbd.stale) {
			previous = mbd;
            //判断这个BeanDefinition的parentName值是不是等于null,由于我们这儿是root,所有这儿是空的
			if (bd.getParentName() == null) {
				// Use copy of given root bean definition.
                //判断这个BeanDefinition的类型是不是RootBeanDefinition的,这儿root是的
				if (bd instanceof RootBeanDefinition) {
                    //克隆这个BeanDefinition
					mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
				}
				else {
                    //若不是也是直接将这个BeanDefinition变成RootBeanDefinition
					mbd = new RootBeanDefinition(bd);
				}
			}
            //这个就是需要的合并的,我们下面会讲
			else {
				// Child bean definition: needs to be merged with parent.
				BeanDefinition pbd;
				try {
					String parentBeanName = transformedBeanName(bd.getParentName());
					if (!beanName.equals(parentBeanName)) {
						pbd = getMergedBeanDefinition(parentBeanName);
					}
					else {
						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 a ConfigurableBeanFactory parent");
						}
					}
				}
				catch (NoSuchBeanDefinitionException ex) {
					throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
							"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
				}
				// Deep copy with overridden values.
				mbd = new RootBeanDefinition(pbd);
				mbd.overrideFrom(bd);
			}

			// Set default singleton scope, if not configured before.
            // 若之前没有配置,直接设置为单例模式
			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.
             // 非单例bean中包含的bean本身不能是单例。
             // 让我们在这里即时纠正 因为这可能是外层bean的父子合并的结果
             // 在这种情况下,原始的内部bean定义将不会继承合并的外部bean的单例状态。
			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)
            // 暂时缓存合并的bean定义
            //(稍后可能仍会重新合并以获取元数据更改)
            // 存到合并的bd的map中去。
			if (containingBd == null && isCacheBeanMetadata()) {
				this.mergedBeanDefinitions.put(beanName, mbd);
			}
		}
		if (previous != null) {
			copyRelevantMergedBeanDefinitionCaches(previous, mbd);
		}
		return mbd;
	}
}

上面的代码就是如果没有设置parentName的属性的话,如果这个BeanDefinition的类型是RootBeanDefinition直接克隆一遍,如果这个BeanDefinition的类型不是RootBeanDefinition的类型的话,就直接创建RootBeanDefinition的对象,将这个BeanDefinition赋值给RootBeanDefinition,最后再设置对应的作用域,同时将这个BeanDefinition存到mergedBeanDefinitions的map中去。上面笔者带着读者看了下,不需要合并的BeanDefinition的类型,下面就看看需要合并的BeanDefinition,还是看上面的代码,具体的代码如下:

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

	synchronized (this.mergedBeanDefinitions) {
		RootBeanDefinition mbd = null;
		RootBeanDefinition previous = null;

		// Check with full lock now in order to enforce the same merged instance.
        // 第一次这个值为空
		if (containingBd == null) {
            //这个取出来的值也是空,因为没有合并过
			mbd = this.mergedBeanDefinitions.get(beanName);
		}

        //上面取出来的值为空,所以这儿会进入这个判断
		if (mbd == null || mbd.stale) {
			previous = mbd;
            //判断这个BeanDefinition的parentName值是不是等于null,由于我们这儿是child,所有这儿不是空的
			if (bd.getParentName() == null) {
				// Use copy of given root bean definition.
                //判断这个BeanDefinition的类型是不是RootBeanDefinition的,这儿root是的
				if (bd instanceof RootBeanDefinition) {
                    //克隆这个BeanDefinition
					mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
				}
				else {
                    //若不是也是直接将这个BeanDefinition变成RootBeanDefinition
					mbd = new RootBeanDefinition(bd);
				}
			}
            //这个时候需要合并
			else {
				// Child bean definition: needs to be merged with parent.
				BeanDefinition pbd;
				try {
                    //取出原始的名称,可能有别名
					String parentBeanName = transformedBeanName(bd.getParentName());
                    //判断两个名称是否是一样的,
					if (!beanName.equals(parentBeanName)) {
                        //又调用了一次合并,等于是递归的调用,因为这个parentName的BeanDefinition的parentName的值也不等于空,
                        //直到找到等于null的,就不合并了,由于我们的parentName的值是root,所有不需要合并,这儿返回的就是root表示的BeanDefinition
						pbd = getMergedBeanDefinition(parentBeanName);
					}
					else {
						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 a ConfigurableBeanFactory parent");
						}
					}
				}
				catch (NoSuchBeanDefinitionException ex) {
					throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
							"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
				}
				// Deep copy with overridden values.
                //将父类的值赋值给通过构造函数创建成RootBeanDefinition赋值给mbd
				mbd = new RootBeanDefinition(pbd);
                //然后将子类特有值进行覆盖
				mbd.overrideFrom(bd);
			}

			// Set default singleton scope, if not configured before.
            // 若之前没有配置,直接设置为单例模式
			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.
             // 非单例bean中包含的bean本身不能是单例。
             // 让我们在这里即时纠正 因为这可能是外层bean的父子合并的结果
             // 在这种情况下,原始的内部bean定义将不会继承合并的外部bean的单例状态。
			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)
            // 暂时缓存合并的bean定义
            //(稍后可能仍会重新合并以获取元数据更改)
            // 存到合并的bd的map中去。
			if (containingBd == null && isCacheBeanMetadata()) {
				this.mergedBeanDefinitions.put(beanName, mbd);
			}
		}
		if (previous != null) {
			copyRelevantMergedBeanDefinitionCaches(previous, mbd);
		}
		return mbd;
	}
}

上面的代码就是递归调用一直合并下去,直到parentName的值为空的时候,这个时候找到对应BeanDefinition,将对应的父的BeanDefinition直接创建成RootBeanDefinition,然后再通过调用mbd.overrideFrom(bd);方法,将子类特有的值进行覆盖,我们来看下覆盖的规则,具体的代码如下:

public void overrideFrom(BeanDefinition other) {
    //如有直接覆盖BeanClassName
	if (StringUtils.hasLength(other.getBeanClassName())) {
		setBeanClassName(other.getBeanClassName());
	}
    //如有作用域直接覆盖作用域
	if (StringUtils.hasLength(other.getScope())) {
		setScope(other.getScope());
	}
    //覆盖是否抽象
	setAbstract(other.isAbstract());
    //如有直接覆盖工厂Bean的姓名
	if (StringUtils.hasLength(other.getFactoryBeanName())) {
		setFactoryBeanName(other.getFactoryBeanName());
	}
    //如有直接覆盖工厂方法名
	if (StringUtils.hasLength(other.getFactoryMethodName())) {
		setFactoryMethodName(other.getFactoryMethodName());
	}
   	//设置Role
	setRole(other.getRole());
    //设置源
	setSource(other.getSource());
	copyAttributesFrom(other);

    //如果不是自己实现的BeanDefinition的话,都是继承这个BeanDefinition的
	if (other instanceof AbstractBeanDefinition) {
		AbstractBeanDefinition otherAbd = (AbstractBeanDefinition) other;
        //如有BeanClass直接覆盖
		if (otherAbd.hasBeanClass()) {
			setBeanClass(otherAbd.getBeanClass());
		}
        //如有构造函数的参数的直接覆盖
		if (otherAbd.hasConstructorArgumentValues()) {
			getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues());
		}
        //如有属性的参数直接覆盖
		if (otherAbd.hasPropertyValues()) {
			getPropertyValues().addPropertyValues(other.getPropertyValues());
		}
        //如果有方法重写直接覆盖
		if (otherAbd.hasMethodOverrides()) {
			getMethodOverrides().addOverrides(otherAbd.getMethodOverrides());
		}
        //设置过懒加载直接覆盖
		Boolean lazyInit = otherAbd.getLazyInit();
		if (lazyInit != null) {
			setLazyInit(lazyInit);
		}
        //设置自动装配的模型
		setAutowireMode(otherAbd.getAutowireMode());
        //设置依赖检查
		setDependencyCheck(otherAbd.getDependencyCheck());
        //设置dependsOn 
		setDependsOn(otherAbd.getDependsOn());
        //设置自动装配的候选对象
		setAutowireCandidate(otherAbd.isAutowireCandidate());
        //Primary注解
		setPrimary(otherAbd.isPrimary());
		copyQualifiersFrom(otherAbd);
        //这两个属性在创建Bean的实例的时候有讲到
		setInstanceSupplier(otherAbd.getInstanceSupplier());
		setNonPublicAccessAllowed(otherAbd.isNonPublicAccessAllowed());
		setLenientConstructorResolution(otherAbd.isLenientConstructorResolution());
        //如有初始化方法,直接设置
		if (otherAbd.getInitMethodName() != null) {
			setInitMethodName(otherAbd.getInitMethodName());
			setEnforceInitMethod(otherAbd.isEnforceInitMethod());
		}
        //如有销毁方法,直接设置
		if (otherAbd.getDestroyMethodName() != null) {
			setDestroyMethodName(otherAbd.getDestroyMethodName());
			setEnforceDestroyMethod(otherAbd.isEnforceDestroyMethod());
		}
        //设置是否是合成的
		setSynthetic(otherAbd.isSynthetic());
		setResource(otherAbd.getResource());
	}
	else {
		getConstructorArgumentValues().addArgumentValues(other.getConstructorArgumentValues());
		getPropertyValues().addPropertyValues(other.getPropertyValues());
		setLazyInit(other.isLazyInit());
		setResourceDescription(other.getResourceDescription());
	}
}

上面的规则,大概就是将子类特有的属性进行赋值到父类的BeanDefinition中去,这就是合并的原理,但是读者可能有一个问题了。我们这儿是先注册的是root,这个时候从mergedBeanDefinitions中取值,这个时候能够取到这个BeanDefinition,如果我们先注册的child的话,这个去root是不是取不到,那怎么办?可能刚才笔者没有细讲,读者可以看如下的代码:

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
	// Quick check on the concurrent map first, with minimal locking.
	RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
	if (mbd != null && !mbd.stale) {
		return mbd;
	}
	return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

可以看到如果这个时候如果从mergedBeanDefinitions取出来的值是空的,这个时候会执行getMergedBeanDefinition(beanName, getBeanDefinition(beanName));,注意看这个方法中调用了getBeanDefinition(beanName),然后我们再来看getBeanDefinition(beanName)代码,具体的代码如下:

public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
	BeanDefinition bd = this.beanDefinitionMap.get(beanName);
	if (bd == null) {
		if (logger.isTraceEnabled()) {
			logger.trace("No bean named '" + beanName + "' found in " + this);
		}
		throw new NoSuchBeanDefinitionException(beanName);
	}
	return bd;
}

可以发现这个getBeanDefinition()是从beanDefinitionMap中拿,这个里面是百分之百有值的。所以这个问题解决了。记住这儿是在调用Bean工厂的后置处理器之前合并BeanDefinition的,那么可能有读者会问,既然后面可以调用Bean工厂的后置处理器来对BeanDefinition的信息进行修改,那么这儿为什么要进行合并?直接等到创建Bean的实例之前再和平就好了,因为这儿合并一次后,后面如果BeanDefinition的信息修改了,那么后面又要合并一次,不是这次的合并是没有意义的吗?其实不然,因为这儿的合并并不是作用普通的BeanDefinition,因为spring有些Bean是开天辟地的,用来扫描的什么的?这些BeanDefinition不会经过对应的Bean工厂的后置处理器修改,因为这些类在是在调用Bean工厂的后置器之前就创建了,所以防止一部分的扩展中用到了parentName,所以在这儿就进行了一次合并。并不冲突,正常的情况下,我们这儿的合并不是在这儿调用,而是在我们扫描出来BeanDefinition后再进行合并的。

4.重新合并BeanDefinition

通过看bean工厂后置处理器的执行流程的方法(invokeBeanFactoryPostProcessors())发现在执行完Bean工厂的后置处理器后并没有进行对应的合并,也就是说在其他的地方肯定有进行了一次合并,因为执行完Bean工厂的后置处理器后,可能会对BeanDefinition的信息进行修改过,所以肯定要重新合并,那么重新合并的代码在哪里呢?这个时候我们只需要用idea工具查找mergedBeanDefinitions的所有的使用地方,找到对应的地方,打上对应的断点,然后看对应的调用栈,具体的如下:

在这里插入图片描述

可以看到上面的注释,是重新合并一次BeanDefinition,具体的调用链如下:

org.springframework.context.support.AbstractApplicationContext#refresh
---> org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
---> org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
---> org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)
---> org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
---> org.springframework.beans.factory.support.AbstractBeanFactory#markBeanAsCreated

可以看到这个markBeanAsCreated的方法的调用是在创建Bean的实例之前,markBeanAsCreated的代码如下:

protected void markBeanAsCreated(String beanName) {
    //判断这个这个Bean是否已经创建,很明显这儿没有创建
	if (!this.alreadyCreated.contains(beanName)) {
		synchronized (this.mergedBeanDefinitions) {
            //双重检查
			if (!this.alreadyCreated.contains(beanName)) {
				// Let the bean definition get re-merged now that we're actually creating
				// the bean... just in case some of its metadata changed in the meantime.
				clearMergedBeanDefinition(beanName);
				this.alreadyCreated.add(beanName);
			}
		}
	}
}

上面是调用clearMergedBeanDefinition(beanName);方法来清楚原来的已经合并好的BeanDefinition,具体的代码如下:

@Override
protected void clearMergedBeanDefinition(String beanName) {
	super.clearMergedBeanDefinition(beanName);
	this.mergedBeanDefinitionHolders.remove(beanName);
}
protected void clearMergedBeanDefinition(String beanName) {
	RootBeanDefinition bd = this.mergedBeanDefinitions.get(beanName);
    //将这个状态设置为true。这个标识的字段只有在false的时候才不会合并,如果是true的话就会合并。
	if (bd != null) {
		bd.stale = true;
	}
}

上面改了一个字段state,这个字段只有在false的时候才不会合并,如果是true时候就会合并,我们可以再次重温一下合并的代码,具体的代码如下:

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
	// Quick check on the concurrent map first, with minimal locking.
	RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
	if (mbd != null && !mbd.stale) {
		return mbd;
	}
	return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

至此整个合并的流程就讲完了。

5.写在最后

这篇博客主要讲了合并BeanDefinition的原理,下篇博客我们继续讲Spring创建Bean的流程。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值