Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理

注:《Spring5源码分析》汇总可参考:Spring5源码分析(002)——博客汇总


  前面已经分析了从单例缓存中获取到有 bean 实例时的处理流程,那从缓存单例中没有获取到 bean 缓存时,Spring 是如何处理的呢?这也是 Spring 统一加载的,而且肯定都是需要去实例化,可以想到的应该有以下两种场景:
  • 1、从父工厂 parentBeanFactory 中进行加载 :如果当前 BeanFactory 的 beanDefinitionMap 中没有相关的 BeanDefinition 定义且存在父工厂时,则通过父工厂 parentBeanFactory 来获取 bean 实例,此时是递归调用 #getBean 的各个重载方法来处理
  • 2、在当前 BeanFactory 中,根据各种 scope 进行 bean 实例化,此时还需要处理的就是相关的依赖 bean ,他们都需要提前实例化。也即是先实例化依赖,然后再根据不同的 scope 来进行实际的实例化。
 
  鉴于根据各种 scope 进行 bean 实例化的过程相对复杂且篇幅较多,接下来的介绍会拆分为两大部分:
  • 第一部分,主要是一些前置检测、通过 parentBeanFactory 获取 bean 实例、依赖 bean 处理,前文中提到的 2.4 - 2.8
  • 第二部分,则是根据各种 scope 进行 bean 的实例化
  本篇主要对第一部分进行分析,也即是在《Spring5源码分析(021)——IoC篇之bean加载》中提到的 2.4 - 2.8 这几个小节所提到的处理,代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory
/// protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly)

// 其他处理代码。。。

// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 4、原型模式的依赖检查
// 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在 A 中有 B 的属性, B 中有 A 的属性,
// 那么当依赖注入的时候,就会产生A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是下面的情况。
// 原型模式下如果存在循环依赖则会抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}

// 5、检查 parentBeanFactory 是否存在对应的 bean
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
// 当前容器中没有找到,则从父类容器中加载
// 如果 beanDefinitionMap 中也就是在所有已经加载的类中不包括 beanName 指定的 bean,
// 则尝试从 parentBeanFactory 中检测
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    // Not found -> check parent.
    String nameToLookup = originalBeanName(name);
    // 递归到 BeanFactory 中寻找
    if (parentBeanFactory instanceof AbstractBeanFactory) {
        return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                nameToLookup, requiredType, args, typeCheckOnly);
    }
    else if (args != null) {
        // Delegation to parent with explicit args.
        return (T) parentBeanFactory.getBean(nameToLookup, args);
    }
    else if (requiredType != null) {
        // No args -> delegate to standard getBean method.
        return parentBeanFactory.getBean(nameToLookup, requiredType);
    }
    else {
        return (T) parentBeanFactory.getBean(nameToLookup);
    }
}

// 6、如果不是仅仅做类型检查则是创建 bean ,这里需要进行记录
if (!typeCheckOnly) {
    markBeanAsCreated(beanName);
}

try {
    // 7、将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition ,
    // 如果指定的 beanName 是子 bean 的话同时会合并父类的相关属性
    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    checkMergedBeanDefinition(mbd, beanName, args);

    // 8、处理依赖的 bean
    // Guarantee initialization of beans that the current bean depends on.
    // 若存在依赖则需要递归实例化依赖的 bean
    String[] dependsOn = mbd.getDependsOn();
    if (dependsOn != null) {
        for (String dep : dependsOn) {
            // 循环依赖的情况,depends-on 是强制依赖
            if (isDependent(beanName, dep)) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
            }
            // 缓存依赖调用
            registerDependentBean(dep, beanName);
            try {
                // 递归调用获取依赖的 bean
                getBean(dep);
            }
            catch (NoSuchBeanDefinitionException ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
            }
        }
    }
/// 其他处理代码。。。

  结合注释可以看出,这段代码主要处理以下这几个部分:

 
本文目录如下:

1、原型模式的依赖检测

  众所周知, Spring 只解决单例模式下的循环依赖,而原型模式下检测到循环依赖则会抛出异常(要不然会陷入无限创建的循环中),这就是 #isPrototypeCurrentlyInCreation(String beanName) 所做的处理,具体代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 4、原型模式的依赖检查
// 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在 A 中有 B 的属性, B 中有 A 的属性,
// 那么当依赖注入的时候,就会产生A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是下面的情况。
// 原型模式下如果存在循环依赖则会抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}

///
/**
 * Return whether the specified prototype bean is currently in creation
 * (within the current thread).
 * @param beanName the name of the bean
 */
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
    Object curVal = this.prototypesCurrentlyInCreation.get();
    return (curVal != null &&
            (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}

/** Names of beans that are currently in creation. */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
        new NamedThreadLocal<>("Prototype beans currently in creation");

  可以看到循环依赖的检测判断有些似曾相识,都是通过正在创建中的集合来判断的,也就是创建时记录和检查,这里是通过 prototypesCurrentlyInCreation 这个 ThreadLocal 来进行记录相关的创建中原型集合的,而这个记录则是在 beforePrototypeCreation(String beanName)afterPrototypeCreation(String beanName) ,这个可以在稍后面的原型实例化创建时看到有相关调用,这里的默认实现就是直接将 beanName 丢到 prototypesCurrentlyInCreation 中。

2、检查 parentBeanFactory 是否存在对应的 bean

  如果当前 BeanFactory 的 beanDefinitionMap 中没有相关的 BeanDefinition 定义,也就是说通过 # containsBeanDefinition(String beanName) 方法获不到对应的bean定义,且存在父工厂时,则通过父工厂 parentBeanFactory 来获取 bean 实例,代码如下:

/// org.springframework.beans.factory.support.AbstractBeanFactory

// 5、检查 parentBeanFactory 是否存在对应的 bean
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
// 当前容器中没有找到,则从父类容器中加载
// 如果 beanDefinitionMap 中也就是在所有已经加载的类中不包括 beanName 指定的 bean,
// 则尝试从 parentBeanFactory 中检测
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    // Not found -> check parent.
    String nameToLookup = originalBeanName(name);
    // 递归到 BeanFactory 中寻找
    if (parentBeanFactory instanceof AbstractBeanFactory) {
        return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                nameToLookup, requiredType, args, typeCheckOnly);
    }
    else if (args != null) {
        // Delegation to parent with explicit args.
        return (T) parentBeanFactory.getBean(nameToLookup, args);
    }
    else if (requiredType != null) {
        // No args -> delegate to standard getBean method.
        return parentBeanFactory.getBean(nameToLookup, requiredType);
    }
    else {
        return (T) parentBeanFactory.getBean(nameToLookup);
    }
}

  这过程其实也好理解,就是递归调用 #getBean 方法来获取实例。需要注意的是,这里的 beanName 是需要做转换的,调用 #originalBeanName(String name) 来处理,代码如下:

/**
 * Determine the original bean name, resolving locally defined aliases to canonical names.
 * @param name the user-specified name
 * @return the original bean name
 */
protected String originalBeanName(String name) {
    String beanName = transformedBeanName(name);
    if (name.startsWith(FACTORY_BEAN_PREFIX)) {
        beanName = FACTORY_BEAN_PREFIX + beanName;
    }
    return beanName;
}
  这里先调用 transformedBeanName(name)(前面文章已经提到过) 来获取真正的 beanName ,然后(如果有的话)再补上 FactoryBean 引用前缀 & 。
 

3、类型检查

  如果不是仅仅做类型检查则是创建 bean ,则需要调用 #markBeanAsCreated(String beanName) 方法,将该 bean 标记为已创建或即将创建。代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

/**
 * Mark the specified bean as already created (or about to be created).
 * <p>This allows the bean factory to optimize its caching for repeated
 * creation of the specified bean.
 * <p>将指定的 bean 标记为已创建或即将创建。
 * <p>这允许 beanFactory 优化其缓存,以重复创建指定的Bean。
 * @param beanName the name of the bean
 */
protected void markBeanAsCreated(String beanName) {
    // 还没有创建
    if (!this.alreadyCreated.contains(beanName)) {
        // 加锁
        synchronized (this.mergedBeanDefinitions) {
            // DCL 双重检查
            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);
                // 添加到已创建 bean 集合中
                this.alreadyCreated.add(beanName);
            }
        }
    }
}

/**
 * Remove the merged bean definition for the specified bean,
 * recreating it on next access.
 * <p>从 mergedBeanDefinitions 中删除指定的 bean ,并在下次访问时重新创建它。
 * @param beanName the bean name to clear the merged definition for
 */
protected void clearMergedBeanDefinition(String beanName) {
    RootBeanDefinition bd = this.mergedBeanDefinitions.get(beanName);
    if (bd != null) {
        bd.stale = true;
    }
}
 

4、将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition

  代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

// 7、将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition ,
// 如果指定的 beanName 是子 bean 的话同时会合并父类的相关属性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
  • 1、这里首先调用 #getMergedLocalBeanDefinition(String beanName) 方法,获取 BeanDefinition 对象,代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

/**
 * Return a merged RootBeanDefinition, traversing the parent bean definition
 * if the specified bean corresponds to a child bean definition.
 * <p>将存储 XML 配置的 GenericBeanDefinition 转换成 RootBeanDefinition ,
 *    如果指定的 beanName 是子bean的话同时会合并父类的相关属性
 * @param beanName the name of the bean to retrieve the merged definition for
 * @return a (potentially merged) RootBeanDefinition for the given bean
 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
 * @throws BeanDefinitionStoreException in case of an invalid bean definition
 */
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));
}

/**
 * Return a RootBeanDefinition for the given top-level bean, by merging with
 * the parent if the given bean's definition is a child bean definition.
 * <p>返回给定顶层 bean 的 RootBeanDefinition ,如果给定的 bean 定义是
 * 子 bean 定义,则会同时合并父bean定义
 * @param beanName the name of the bean definition
 * @param bd the original bean definition (Root/ChildBeanDefinition)
 * @return a (potentially merged) RootBeanDefinition for the given bean
 * @throws BeanDefinitionStoreException in case of an invalid bean definition
 */
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
        throws BeanDefinitionStoreException {

    return getMergedBeanDefinition(beanName, bd, null);
}

/**
 * Return a RootBeanDefinition for the given bean, by merging with the
 * parent if the given bean's definition is a child bean definition.
 * @param beanName the name of the bean definition
 * @param bd the original bean definition (Root/ChildBeanDefinition)
 * @param containingBd the containing bean definition in case of inner bean,
 * or {@code null} in case of a top-level bean
 * @return a (potentially merged) RootBeanDefinition for the given bean
 * @throws BeanDefinitionStoreException in case of an invalid bean definition
 */
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;
            // 没有父bean
            if (bd.getParentName() == null) {
                // Use copy of given root bean definition.
                if (bd instanceof RootBeanDefinition) {
                    mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                }
                else {
                    mbd = new RootBeanDefinition(bd);
                }
            }
            else {
                // 需要合并父bean定义
                // 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 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.
                mbd = new RootBeanDefinition(pbd);
                mbd.overrideFrom(bd);
            }

            // Set default singleton scope, if not configured before.
            // 设置默认 scope
            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.
            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()) {
                this.mergedBeanDefinitions.put(beanName, mbd);
            }
        }
        if (previous != null) {
            copyRelevantMergedBeanDefinitionCaches(previous, mbd);
        }
        return mbd;
    }
}
    • 先从缓存 mergedBeanDefinitions 中获取 RootBeanDefinition 对象,如果存在且不需要重新合并,则直接返回;
    • 否则调用 #getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) 获取。前面从 bean 的解析过程中我们可以知道,从 xml 配置文件中读取到的 bean 信息是存储在 GenericBeanDefinition 中的,而 Spring 中所有的 bean 后续的处理都是针对 RootBeanDefinition 的,因此这里需要进行一个转换,转换的同时如果父类 bean 不为空的话,则会一并合并父类的属性,感兴趣的可以进一步深入研究。
  • 2、调用 #checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args) 方法,对 RootBeanDefinition 进行校验,这里只是检查是否是抽象类。
/**
 * Check the given merged bean definition,
 * potentially throwing validation exceptions.
 * @param mbd the merged bean definition to check
 * @param beanName the name of the bean
 * @param args the arguments for bean creation, if any
 * @throws BeanDefinitionStoreException in case of validation failure
 */
protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
        throws BeanDefinitionStoreException {

    if (mbd.isAbstract()) {
        throw new BeanIsAbstractException(beanName);
    }
}

5、依赖处理

  如果需要获取的 bean 有依赖,则需要确保相关依赖先初始化,代码如下:

// 8、处理依赖的 bean
// Guarantee initialization of beans that the current bean depends on.
// 若存在依赖则需要递归实例化依赖的 bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
    for (String dep : dependsOn) {
        // 循环依赖的情况,depends-on 是强制依赖
        if (isDependent(beanName, dep)) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
        }
        // 缓存依赖调用
        registerDependentBean(dep, beanName);
        try {
            // 递归调用获取依赖的 bean
            getBean(dep);
        }
        catch (NoSuchBeanDefinitionException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
        }
    }
}

  主要逻辑还是循环依赖检测、缓存注册,然后递归调用 #getBean 方法进行 bean 依赖的实例化。

5.1、isDependent

  该方法用于确定指定的依赖Bean是否已注册为依赖于给定Bean或依赖于其任何传递依赖项,递归检测,其实就是循环依赖检测,因为 depends-on 是强制依赖,不能有循环依赖

/// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

/** Map between dependent bean names: bean name to Set of dependent bean names.
 * <p>存放映射关系(依赖谁集合): beanName --> 依赖的 beanNames 集合,即 [canonicalName --> dependentBeanName set] */
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

/**
 * Determine whether the specified dependent bean has been registered as
 * dependent on the given bean or on any of its transitive dependencies.
 * <p>确定指定的依赖Bean是否已注册为依赖于给定Bean或依赖于其任何传递依赖项。
 * @param beanName the name of the bean to check
 * @param dependentBeanName the name of the dependent bean
 * @since 4.0
 */
protected boolean isDependent(String beanName, String dependentBeanName) {
    synchronized (this.dependentBeanMap) {
        return isDependent(beanName, dependentBeanName, null);
    }
}

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    // 获取真正的 beanName
    String canonicalName = canonicalName(beanName);
    // 当前 beanName 依赖的bean集合
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    if (dependentBeans == null) {
        return false;
    }
    // 存在则说明存在循环依赖
    if (dependentBeans.contains(dependentBeanName)) {
        return true;
    }
    // 对所有依赖进行递归检测
    for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) {
            alreadySeen = new HashSet<>();
        }
        // 添加到 alreadySeen 中
        alreadySeen.add(beanName);
        // 递归调用检测
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
            return true;
        }
    }
    return false;
}

5.2、registerDependentBean

  为给定的 bean 注册一个依赖 bean,在销毁指定的 bean 之前销毁该 bean,其实就是记录“谁依赖哪些谁”、“谁被哪些谁依赖”之间的映射。需要说明的是, depends-on 是一种强制依赖初始化,不能有循环依赖,因此这里进行了注册判断。代码如下:

/**
 * Register a dependent bean for the given bean,
 * to be destroyed before the given bean is destroyed.
 * <p>为给定的 bean 注册一个依赖 bean,在销毁指定的 bean 之前销毁该 bean
 * @param beanName the name of the bean
 * @param dependentBeanName the name of the dependent bean
 */
public void registerDependentBean(String beanName, String dependentBeanName) {
    // 获取真正的 beanName
    String canonicalName = canonicalName(beanName);

    // 添加 [canonicalName --> dependentBeanName set] 到 dependentBeanMap 中
    synchronized (this.dependentBeanMap) {
        Set<String> dependentBeans =
                this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
        if (!dependentBeans.add(dependentBeanName)) {
            return;
        }
    }

    // 添加 [dependentBeanName --> canonicalName set] 到 dependenciesForBeanMap 中
    synchronized (this.dependenciesForBeanMap) {
        Set<String> dependenciesForBean =
                this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
        dependenciesForBean.add(canonicalName);
    }
}

 

5.3、getBean

  这里就是通过递归调用 #getBean 方法实例化依赖的 bean 。 

6、参考

原文地址:https://www.cnblogs.com/wpbxin/p/14968540.html