在 Spring 种,所有的 BD 都会进行合并(Merger),为什么要进行合并呢?因为可能存在父 BD 的情况,所以要进行合并

    即:所有的 Bean 最终都会合并成一个 BD,也就是 RootBeanDefinition

    Spring 在合并 BD,第一次是在扫描 Bean 的时候,此时只会合并已经存在的 BD,和手动通过容器注册的 BD( ac.registerBeanDefinition,其他的比如通过 BeanFactoryProcessor 注册的 bean,则会再 preInstantiateSingletons 的时候完成合并,因为 BeanFactoryProcessor 执行的时机晚于扫描 Bean 的时机),才会再第一次扫描的时候完成合并,然后 Spring 又会将其从 mergedBeanDefinitions 中清除掉,加入到 alreadyCreated 集合中去(这样做的目的是防止后面会对这个 Bean 做更改),然后继续进行一次合并

    1. // ★★★ 此时已经经过扫描
    2. // 此时第二次调用 getBeanNamesForType 可以拿到所有的 BD,同时完成了第一次的 BD 合并
    3. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    4. ...
    5. // 开始进行合并
    6. RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

    以下,是完成合并的关键代码:

    1. protected RootBeanDefinition getMergedBeanDefinition(
    2. String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
    3. throws BeanDefinitionStoreException {
    4. synchronized (this.mergedBeanDefinitions) {
    5. // 用 RootBeanDefinition 记录合并之后 bd
    6. // 可能是 本身,也可能是 父类
    7. RootBeanDefinition mbd = null;
    8. // Check with full lock now in order to enforce the same merged instance.
    9. if (containingBd == null) {
    10. mbd = this.mergedBeanDefinitions.get(beanName);
    11. }
    12. if (mbd == null) {
    13. // 判断是否需要合并,如果 ParentName 为空,则不需要进行合并
    14. if (bd.getParentName() == null) {
    15. // Use copy of given root bean definition.
    16. // 如果是 RootBeanDefinition
    17. if (bd instanceof RootBeanDefinition) {
    18. // 因为没有父类,所以直接 clone 给 RootBeanDefinition
    19. mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
    20. }
    21. else {
    22. // 构建了一个 RootBeanDefinition
    23. mbd = new RootBeanDefinition(bd);
    24. }
    25. }
    26. // 需要合并
    27. else {
    28. // Child bean definition: needs to be merged with parent.
    29. BeanDefinition pbd;
    30. try {
    31. // 获取 父类 的名字
    32. String parentBeanName = transformedBeanName(bd.getParentName());
    33. if (!beanName.equals(parentBeanName)) {
    34. // 得到父类的 BD,这里是一个递归调用,是因为父类可能还有父类
    35. pbd = getMergedBeanDefinition(parentBeanName);
    36. }
    37. else {
    38. BeanFactory parent = getParentBeanFactory();
    39. if (parent instanceof ConfigurableBeanFactory) {
    40. pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
    41. }
    42. else {
    43. throw new NoSuchBeanDefinitionException(parentBeanName,
    44. "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
    45. "': cannot be resolved without an AbstractBeanFactory parent");
    46. }
    47. }
    48. }
    49. catch (NoSuchBeanDefinitionException ex) {
    50. throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
    51. "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
    52. }
    53. // Deep copy with overridden values.
    54. // ★ 以父类为基准,先父类的 BD 合并到 RootBeanDefinition
    55. mbd = new RootBeanDefinition(pbd);
    56. // ★★★ 子类 覆盖 父类的 bean 属性
    57. mbd.overrideFrom(bd);
    58. }
    59. // Set default singleton scope, if not configured before.
    60. if (!StringUtils.hasLength(mbd.getScope())) {
    61. mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
    62. }
    63. // A bean contained in a non-singleton bean cannot be a singleton itself.
    64. // Let's correct this on the fly here, since this might be the result of
    65. // parent-child merging for the outer bean, in which case the original inner bean
    66. // definition will not have inherited the merged outer bean's singleton status.
    67. if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
    68. mbd.setScope(containingBd.getScope());
    69. }
    70. // Cache the merged bean definition for the time being
    71. // (it might still get re-merged later on in order to pick up metadata changes)
    72. if (containingBd == null && isCacheBeanMetadata()) {
    73. // 合并完成之后,将放人 RootBeanDefinition 放入 mergedBeanDefinitions 中
    74. this.mergedBeanDefinitions.put(beanName, mbd);
    75. }
    76. }
    77. return mbd;
    78. }
    79. }

    总体来说:合并 BD,其实就是先寻找当前 BD 的父 BD,如果没有父 BD,则直接克隆当前 BD,交给 RootBeanDefinition,如果存在父 BD,则找到父 BD(此处会经过一个递归调用来寻找底层父 BD),然后先将父 BD 复制给一个新的 RootBeanDefinition,然后再找到子 BD 进行值的替换,就完成了一个完整的 BD