BeanDefinition的合并

225 阅读2分钟

BeanDefinition 的合并

Spring 在使用 BeanDefinition 创建 Bean 之前,会对 BeanDefinition 进行合并和检查。这部分代码位于 AbstractBeanFactory#getMergedLocalBeanDefinition 中

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

  //合并好的BeanDefinition的缓存
  private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

  //获取一个beanName的合并BeanDefinition ,一般都是调用此方法
	protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    //1 检查缓存
    // 没有 或者 过期了则重新合并
		RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
		if (mbd != null && !mbd.stale) {
			return mbd;
		}
    // 2 合并BeanDefinition
    // 先调用 getBeanDefinition方法,getBeanDefinition方法并不会进行合并,而是一直保持BeanDefintion最初定义时候的样子
		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
	}

  //再套一层
  protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
			throws BeanDefinitionStoreException {

		return getMergedBeanDefinition(beanName, bd, null);
	}

  //最终合并BeanDefinition的方法
  // beanName     bean的名字
  // bd           原始的BeanDefinition
  // containingBd 如果是内部bean,则包含bean定义,如果是顶级bean,则为null
  protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
		throws BeanDefinitionStoreException {

    //0 整体代码加锁,多线程场景下,同一beanName被多个线程调用合并方法时,造成合并的不一致
		synchronized (this.mergedBeanDefinitions) {
      // mbd 最终的合并结果
			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;//如果是重新合并的,则此时mbd不会为null,mbd.stale为true,此时使用一个previous来保持对合并前的
        // 1 如果没有父定义,则不需要合并,稍微包装下就可以返回
				if (bd.getParentName() == null) {
					// Use copy of given root bean definition.
					if (bd instanceof RootBeanDefinition rootBeanDef) {
						mbd = rootBeanDef.cloneBeanDefinition();
					}
					else {
						mbd = new RootBeanDefinition(bd);
					}
				}
				else {
          // 2 有父定义,需要进行递归合并
					BeanDefinition pbd;//父定义
					try {
						String parentBeanName = transformedBeanName(bd.getParentName());
            // 当前beanName不等于arentBeanName,则递归调用最上层的getMergedBeanDefinition方法,即把父定义递归合并好
						if (!beanName.equals(parentBeanName)) {
							pbd = getMergedBeanDefinition(parentBeanName);
						}
						else {
              // 如果重名,则应该是在父容器中,则去父容器中去寻找,如果没有父容器,说明出现了错误的配置,即自己的parent就是自己!需要抛出异常
							if (getParentBeanFactory() instanceof ConfigurableBeanFactory parent) {
								pbd = 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) {//这里说明引用了一个不存在的父BeanDefinition
						throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
								"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
					}
					//3  Deep copy with overridden values.
          //把父定义的属性深拷贝一份
					mbd = new RootBeanDefinition(pbd);

          //4 把当前BeanDefintion的属性覆盖写到mbd中
					mbd.overrideFrom(bd);
				}

        //5 设置缺失属性 scope=单例
				if (!StringUtils.hasLength(mbd.getScope())) {
					mbd.setScope(SCOPE_SINGLETON);
				}

        // 6 如果容器Bean不是单例的,而当前Bean是单例的,那么当前Bean的scope需要变成与容器Bean相同
				if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
					mbd.setScope(containingBd.getScope());
				}

        // 7 缓存合并好的BeanDefinition
				if (containingBd == null && isCacheBeanMetadata()) {
					this.mergedBeanDefinitions.put(beanName, mbd);
				}
			}
			if (previous != null) {
				copyRelevantMergedBeanDefinitionCaches(previous, mbd);
			}
			return mbd;
		}
	}

	//把旧BeanDefintion的一些特殊属性复制到新的BeanDefintion上
	private void copyRelevantMergedBeanDefinitionCaches(RootBeanDefinition previous, RootBeanDefinition mbd) {
		if (ObjectUtils.nullSafeEquals(mbd.getBeanClassName(), previous.getBeanClassName()) &&
				ObjectUtils.nullSafeEquals(mbd.getFactoryBeanName(), previous.getFactoryBeanName()) &&
				ObjectUtils.nullSafeEquals(mbd.getFactoryMethodName(), previous.getFactoryMethodName())) {
			ResolvableType targetType = mbd.targetType;
			ResolvableType previousTargetType = previous.targetType;
			if (targetType == null || targetType.equals(previousTargetType)) {
				mbd.targetType = previousTargetType;
				mbd.isFactoryBean = previous.isFactoryBean;
				mbd.resolvedTargetType = previous.resolvedTargetType;
				mbd.factoryMethodReturnType = previous.factoryMethodReturnType;
				mbd.factoryMethodToIntrospect = previous.factoryMethodToIntrospect;
			}
		}
	}
}