在 Spring 种,所有的 BD 都会进行合并(Merger),为什么要进行合并呢?因为可能存在父 BD 的情况,所以要进行合并
即:所有的 Bean 最终都会合并成一个 BD,也就是 RootBeanDefinition
Spring 在合并 BD,第一次是在扫描 Bean 的时候,此时只会合并已经存在的 BD,和手动通过容器注册的 BD( ac.registerBeanDefinition,其他的比如通过 BeanFactoryProcessor 注册的 bean,则会再 preInstantiateSingletons 的时候完成合并,因为 BeanFactoryProcessor 执行的时机晚于扫描 Bean 的时机),才会再第一次扫描的时候完成合并,然后 Spring 又会将其从 mergedBeanDefinitions 中清除掉,加入到 alreadyCreated 集合中去(这样做的目的是防止后面会对这个 Bean 做更改),然后继续进行一次合并
// ★★★ 此时已经经过扫描
// 此时第二次调用 getBeanNamesForType 可以拿到所有的 BD,同时完成了第一次的 BD 合并
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
...
// 开始进行合并
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
以下,是完成合并的关键代码:
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
// 用 RootBeanDefinition 记录合并之后 bd
// 可能是 本身,也可能是 父类
RootBeanDefinition mbd = 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) {
// 判断是否需要合并,如果 ParentName 为空,则不需要进行合并
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
// 如果是 RootBeanDefinition
if (bd instanceof RootBeanDefinition) {
// 因为没有父类,所以直接 clone 给 RootBeanDefinition
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
// 构建了一个 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)) {
// 得到父类的 BD,这里是一个递归调用,是因为父类可能还有父类
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 an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
// ★ 以父类为基准,先父类的 BD 合并到 RootBeanDefinition
mbd = new RootBeanDefinition(pbd);
// ★★★ 子类 覆盖 父类的 bean 属性
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.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.
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)
if (containingBd == null && isCacheBeanMetadata()) {
// 合并完成之后,将放人 RootBeanDefinition 放入 mergedBeanDefinitions 中
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
总体来说:合并 BD,其实就是先寻找当前 BD 的父 BD,如果没有父 BD,则直接克隆当前 BD,交给 RootBeanDefinition,如果存在父 BD,则找到父 BD(此处会经过一个递归调用来寻找底层父 BD),然后先将父 BD 复制给一个新的 RootBeanDefinition,然后再找到子 BD 进行值的替换,就完成了一个完整的 BD