zoukankan      html  css  js  c++  java
  • 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、参考

  • 相关阅读:
    SGU 176.Flow construction (有上下界的最大流)
    POJ 2391.Ombrophobic Bovines (最大流)
    poj 1087.A Plug for UNIX (最大流)
    poj 1273.PIG (最大流)
    POJ 2112.Optimal Milking (最大流)
    SGU 196.Matrix Multiplication
    SGU 195. New Year Bonus Grant
    关于multicycle path
    ppt做gif动图
    codeforces 598A Tricky Sum
  • 原文地址:https://www.cnblogs.com/wpbxin/p/14968540.html
Copyright © 2011-2022 走看看