Spring5源码分析(021)——IoC篇之bean加载

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

  下面这张是前面文章也有贴出来的官网给的 IoC 容器如何工作的顶层视图: https://docs.spring.io/spring-framework/docs/5.2.3.RELEASE/spring-framework-reference/core.html#beans-basics
  之前提到过,Spring IoC 容器的主要功能就是加载配置元数据 Configuration Metadata ,解析、组装、存储,然后根据解析后的封装 BeanDefinition 来完成 bean 的加载,最终成为一个完全可用的容器,Spring容器实现这些功能时主要分为两个阶段:
  • 1、容器初始化(bean配置解析)
    • 首先,通过多种方式加载相应的配置元数据 Configuration Metadata (使用 Resource 体系 和 ResourceLoader)
    • 其次,对加载的配置进行解析,组装成对应的 BeanDefinition (BeanDefinition 体系 和 BeanDefinitionReader 体系)
    • 然后,将解析后的 BeanDefinition 注册存储到 BeanDefinitionRegistry 中(BeanFactory 体系)
    • 最后,完成容器初始化
  • 2、bean加载和使用
    • 容器的初始化只是完成了 bean 配置的解析,还需要通过 bean 加载阶段才能真正使用 bean ,这是通过显式或者隐式调用 BeanFactory#getBean(...) 时触发的
    • bean 加载首先会检查所请求的对象是否已经加载初始化了,如果没有,则会根据解析注册的 bean 信息完成相关的初始化和依赖注入,然后将初始化完成的对象返回
    • bean 加载完成后就可以直接使用返回的 bean 来进行相关操作了。
  前面花了比较多篇幅的介绍,都是对 xml 配置文件的解析分析,也即是上面提到的第一部分【容器初始化(bean配置解析)】,接下来的重点则是对应的 bean 加载,即第二部分【bean 的加载阶段】。毕竟 xml 解析(或者说配置解析)后只是得到相应的 bean 定义 BeanDefinition ,而我们需要使用的则是 bean ,因此还需要通过 BeanDefinition 加载得到对应的 bean ,也即是 bean 的加载。bean 加载的功能实现也是相当地复杂。我们还是从源码出发,看看 bean 加载的整个过程,其中涉及到哪些步骤,进而开启本系列文章第二部分的解析分析:
@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

  本文目录结构如下:

 

1、getBean(String name)

  bean 容器初始化完成后,我们就可以简单地通过调用 getBean(String name) 方法就获取到我们需要的 bean ,然后像正常一样(主动 new 的方式)使用这个 bean 。getBean(String name) 方法如下:
@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

  getBean(String name) 方法内部其实是委托给 doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 进行处理,其参数说明如下:

  • name : 需要获取的 bean 名称,可能是真正的 beanName ,有可能是别名,还可能是带 FactoryBean 前缀 & 的名称
  • requiredType : 需要获取的 bean 的类型
  • args : 创建 bean 时传递的参数,仅限于创建 bean 时使用
  • typeCheckOnly : 是否仅仅只是类型检查
  接下来,我们重点关注这个方法,它包含了 bean 加载的一整个过程。
 

2、doGetBean(...)

  doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 方法是接下来的分析重点,代码非常长,逻辑也非常复杂,其中涉及到各种各样的考虑,阅读这部分代码时需要细心更需要耐心,doGetBean 方法的代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory
/**
 * Return an instance, which may be shared or independent, of the specified bean.
 * <p>返回指定 bean 的一个实例,该实例可以是共享的,也可以是独立(原型)的。
 * @param name the name of the bean to retrieve
 * @param requiredType the required type of the bean to retrieve
 * @param args arguments to use when creating a bean instance using explicit arguments
 * (only applied when creating a new instance as opposed to retrieving an existing one)
 * @param typeCheckOnly whether the instance is obtained for a type check,
 * not for actual use
 * @return an instance of the bean
 * @throws BeansException if the bean could not be created
 */
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    // 1、转换对应的 beanName
    // 会去掉 FactoryBean 工厂 bean 引用前缀 ( & ),并将别名(如果是)转化成映射的 beanName
    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    /*
     * 2、从缓存或者实例工厂中获取单例 bean 对象:检查缓存中或者实例工厂中是否有对应的 bean 实例
     * 为什么需要使用这段代码,来检查缓存?
     * 因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免依赖循环,
     * Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提前曝光,
     * 也就是将 ObjectFactory 加入到缓存中,一旦下个 bean 创建时需要依赖上个 bean 则直接使用 ObjectFactory
     */
    // 检查注册的单例缓存中是否有对应的单例
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isTraceEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        // 返回对应的实例,有时候存在诸如 FactoryBean 的情况下,可能返回 FactoryBean 本身,
        // 也有可能返回的是 FactoryBean 指定方法返回的实例
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

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

        // 4、检查 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);
            }
        }

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

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

            // 7、处理依赖的 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);
                    }
                }
            }

            // 8、针对不同 scope 进行 bean 的实例化
            // Create bean instance.
            // 实例化依赖的 bean 创建之后便可以实例化 mbd 本身了
            // singleton 模式的创建
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        // Explicitly remove instance from singleton cache: It might have been put there
                        // eagerly by the creation process, to allow for circular reference resolution.
                        // Also remove any beans that received a temporary reference to the bean.
                        // 显式从单例缓存中删除bean实例
                        // 因为单例模式下为了解决循环依赖,可能已经存在了,所以销毁它
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                // 从bean实例中获取对象,获取Bean实例本身或其创建的对象(如果是 FactoryBean)
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            // prototype 原型模式下的创建(new)
            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    // 1)、创建前的前置处理
                    beforePrototypeCreation(beanName);
                    // 2)、创建 bean 实例对象
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    // 3)、创建后的后置处理
                    afterPrototypeCreation(beanName);
                }
                // 4)、从bean实例中获取对象,则获取Bean实例本身或其创建的对象(如果是 FactoryBean)
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            // 指定的 scope 下实例化 bean
            else {
                // 获取指定 scopeName 的 Scope 对象
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    // 通过指定的 scope 对象来创建和实例化 bean
                    Object scopedInstance = scope.get(beanName, () -> {
                        // 1)、创建前的前置处理
                        beforePrototypeCreation(beanName);
                        try {
                            // 2)、创建 bean 实例对象
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            // 3)、创建后的后置处理
                            afterPrototypeCreation(beanName);
                        }
                    });
                    // 4)、从bean实例中获取对象
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // 9、类型转换 : 检查需要的类型是否符合 bean 的实际类型
    // Check if required type matches the type of the actual bean instance.
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isTraceEnabled()) {
                logger.trace("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

  比较少有的一个长方法,可见逻辑相当的复杂,根据上面给出的部分代码注释,可以粗略地了解 Spring 加载 bean 的整个过程,而对于加载过程所涉及的步骤大致如下:

 

2.1、转换对应的 beanName

  对应的调用代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

// 1、转换对应的 beanName
// 会去掉 FactoryBean 工厂 bean 引用前缀 ( & ),并将别名(如果是)转化成映射的 beanName
final String beanName = transformedBeanName(name);
  之所以需要转换对应的 beanName ,是因为除了通过 beanName 获取 bean 之外,还很可能通过别名、 FactoryBean 等方式,因此需要一系列的解析转换,这些解析包括如下内容:
  • 1、去除 FactoryBean 的前缀修饰符 “&”,例如传入的参数 name = "&myBeanName",那么首先会去除 & ,剩下的就是 “myBeanName”,这里还会去除重复的 & 前缀,具体参考 org.springframework.beans.factory.BeanFactoryUtils#transformedBeanName(String name)
  • 2、取指定的 alias 所表示的最终的 beanName ,例如别名 A 指向名称为 B 的 bean 则返回 B;如果 B 也是别名,且别名 B 指向的是名称为 C 的 bean 则返回 C,具体参考 org.springframework.core.SimpleAliasRegistry#canonicalName(String name)
  这些就是 transformedBeanName(String name) 中需要处理的内容,其代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

/**
 * Return the bean name, stripping out the factory dereference prefix if necessary,
 * and resolving aliases to canonical names.
 * <p>返回 beanName ,必要时去掉 FactoryBean 引用前缀 ( & ) ,并将别名解析为规范名称。
 * @param name the user-specified name
 * @return the transformed bean name
 */
protected String transformedBeanName(String name) {
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
  可以看到 transformedBeanName(String name) 方法委托给另外2个方法分别处理了上面这2个步骤,即:
  • 1、通过调用 BeanFactoryUtils#transformedBeanName(String name) 方法,去除重复的 FactoryBean 引用前缀修饰符 ( & ),代码如下:
/// org.springframework.beans.factory.BeanFactoryUtils

/**
 * Cache from name with factory bean prefix to stripped name without dereference.
 * <p>缓存 {@link #transformedBeanName(String)} 已经转换好的结果(去掉 BeanFactory 前缀 & )
 * @since 5.1
 * @see BeanFactory#FACTORY_BEAN_PREFIX
 */
private static final Map<String, String> transformedBeanNameCache = new ConcurrentHashMap<>();

/**
 * Return the actual bean name, stripping out the factory dereference
 * prefix (if any, also stripping repeated factory prefixes if found).
 * <p>返回实际的 beanName,去掉 FactoryBean 前缀 &(如果有,也会去掉重复的前缀)
 * @param name the name of the bean
 * @return the transformed name
 * @see BeanFactory#FACTORY_BEAN_PREFIX
 */
public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    // 不是 & 开头直接返回
    if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        return name;
    }
    // 去掉所有的 & 前缀,然后缓存到 transformedBeanNameCache 中
    return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
        do {
            beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
        }
        while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
        return beanName;
    });
}
  • 2、通过调用 SimpleAliasRegistry#canonicalName(String name) 方法,来获取最终的 beanName ,代码如下:
    • 这里其实主要是一个循环获取 beanName 的过程,例如 a -> b , b -> c , c -> beanName,则最终返回 beanName 。
/// org.springframework.core.SimpleAliasRegistry

/**
 * Determine the raw name, resolving aliases to canonical names.
 * <p>确定原始名称,将别名解析为规范名称。
 * @param name the user-specified name
 * @return the transformed name
 */
public String canonicalName(String name) {
    String canonicalName = name;
    // 循环处理别名,例如 a -> b , b -> c , c -> beanName
    // Handle aliasing...
    String resolvedName;
    do {
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
            canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}

  

2.2、从缓存中获取单例 bean

  对应的调用代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

// Eagerly check singleton cache for manually registered singletons.
/*
 * 2、从缓存或者实例工厂中获取单例 bean 对象:检查缓存中或者实例工厂中是否有对应的 bean 实例
 * 为什么需要使用这段代码,来检查缓存?
 * 因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免依赖循环,
 * Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提前曝光,
 * 也就是将 ObjectFactory 加入到缓存中,一旦下个 bean 创建时需要依赖上个 bean 则直接使用 ObjectFactory
 */
// 检查注册的单例缓存中是否有对应的单例
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
    if (logger.isTraceEnabled()) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                    "' that is not fully initialized yet - a consequence of a circular reference");
        }
        else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
        }
    }
    // 返回对应的实例,有时候存在诸如 FactoryBean 的情况下,可能返回 FactoryBean 本身,
    // 也有可能返回的是 FactoryBean 指定方法返回的实例
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
  单例在 Spring 中的同一个容器中只会实例化创建一次,后续再次获取 bean ,都是直接从单例缓存中获取,这样就保证了单例 bean 的唯一性。
  • 1、这里的从缓存中获取单例 bean ,其实也只是尝试加载,首先尝试从单例缓存 singletonObjects 中加载,然后再次尝试从 earlySingletonObjects 中加载,之后再尝试从 singletonFactories 中获取,因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖, Spring 中创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 并提前曝光加入到缓存中,一旦下一个 bean 创建时候需要依赖上一个 bean 则直接使用 ObjectFactory (这就是循环依赖的处理,后面的文章会对此进行重点讲解)。
  • 2、如果从缓存中得到了 bean 的原始状态,还需要对 bean 进一步处理。缓存中记录的只是最原始的 bean 状态,并不一定是我们最终想要的 bean 。例如,当我们需要对 FactoryBean 即工厂 bean 进行处理,那么这里得到的其实是工厂 bean 的初始状态,但是我们真正需要的是工厂 bean 中定义的 factory-method 方法中返回的 bean ,而 getObjectForBeanInstance 方法就是来完成这些处理的,也有可能是需要返回 FactoryBean 本身,例如存在 & 前缀时。
  从缓存中获取单例 bean 的详细分析,参考:《Spring5源码分析(023)——IoC篇之bean加载:从缓存中获取单例 bean
 

2.3、原型模式的依赖检测

  对应的调用代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 3、原型模式的依赖检查
// 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在 A 中有 B 的属性, B 中有 A 的属性,
// 那么当依赖注入的时候,就会产生A还未创建完的时候因为对于B的创建再次返回创建A,造成循环依赖,也就是下面的情况。
// 原型模式下如果存在循环依赖则会抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
    throw new BeanCurrentlyInCreationException(beanName);
}
  众所周知, Spring 只有在单例情况下才会尝试解决循环依赖:
  • 原型模式情况下,如果存在 A 中有 B 的属性, B 中有 A 的属性,那么当依赖注入的时候,就会产生A还未创建完的时候因为对于B的创建再次返回创建A,这就造成了造成循环依赖,也即是 isPrototypeCurrentlyInCreation(beanName) 为 true 的情况。
  • 单例模式下,因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在 Spring 中创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 并提前曝光加入到缓存中,一旦下一个 bean 创建时候需要依赖上一个 bean 则直接使用 ObjectFactory (第3步中提到的)。
  相关分析可以参考:《Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理
 

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

  对应的调用代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

// 4、检查 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);
    }
}

  从代码上看,如果当前缓存中没有对应的 bean 的话则直接转到父类工厂中去加载。这是存在继承的情况下才会出现的场景,也即是存在父类 BeanFactory 即 parentBeanFactory ,且当前 BeanFactory 中找到不到相关的 bean 定义(没有相关的bean定义 BeanDefinition ),就会委托 parentBeanFactory ,通过 parentBeanFactory 递归调用 getBean 方法进行获取 bean 。具体分析参考:《Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理

 

2.5、类型检查

  对应的调用代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

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

类型检查,将指定的 bean 标记为已创建或即将创建,具体分析参考:《Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理

 

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

  对应的调用代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

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

  前面从 bean 的解析过程中我们可以知道,从 xml 配置文件中读取到的 bean 信息是存储在 GenericBeanDefinition 中的,而 Spring 中所有的 bean 后续的处理都是针对 RootBeanDefinition 的,因此这里需要进行一个转换,转换的同时如果父类 bean 不为空的话,则会一并合并父类的属性。详细的分析请参考:《Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理

 

2.7、依赖处理

  对应的调用代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

// 7、处理依赖的 bean
// Guarantee initialization of beans that the current bean depends on.
// 若存在依赖则需要递归实例化依赖的 bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
    for (String dep : dependsOn) {
        // 循环依赖的情况
        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);
        }
    }
}

  因为 bean 的初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的 bean ,那么这个时候就有必要先加载依赖的bean ,所以,在 Spring 的加载顺序中,在初始化某一个 bean 的时候首先会初始化这个 bean 所对应的依赖。详细的分析请参考:《Spring5源码分析(024)——IoC篇之bean加载:parentBeanFactory和依赖处理

 

2.8、针对不同scope进行bean的创建

  对应的调用代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

// 8、针对不同 scope 进行 bean 的实例化
// Create bean instance.
// 实例化依赖的 bean 创建之后便可以实例化 mbd 本身了
// singleton 模式的创建
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            // Also remove any beans that received a temporary reference to the bean.
            // 显式从单例缓存中删除bean实例
            // 因为单例模式下为了解决循环依赖,可能已经存在了,所以销毁它
            destroySingleton(beanName);
            throw ex;
        }
    });
    // 从bean实例中获取对象,获取Bean实例本身或其创建的对象(如果是 FactoryBean)
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

// prototype 原型模式下的创建(new)
else if (mbd.isPrototype()) {
    // It's a prototype -> create a new instance.
    Object prototypeInstance = null;
    try {
        // 1)、创建前的前置处理
        beforePrototypeCreation(beanName);
        // 2)、创建 bean 实例对象
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        // 3)、创建后的后置处理
        afterPrototypeCreation(beanName);
    }
    // 4)、从bean实例中获取对象,则获取Bean实例本身或其创建的对象(如果是 FactoryBean)
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

// 指定的 scope 下实例化 bean
else {
    // 获取指定 scopeName 的 Scope 对象
    String scopeName = mbd.getScope();
    final Scope scope = this.scopes.get(scopeName);
    if (scope == null) {
        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
    }
    try {
        // 通过指定的 scope 对象来创建和实例化 bean
        Object scopedInstance = scope.get(beanName, () -> {
            // 1)、创建前的前置处理
            beforePrototypeCreation(beanName);
            try {
                // 2)、创建 bean 实例对象
                return createBean(beanName, mbd, args);
            }
            finally {
                // 3)、创建后的后置处理
                afterPrototypeCreation(beanName);
            }
        });
        // 4)、从bean实例中获取对象
        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
    }
    catch (IllegalStateException ex) {
        throw new BeanCreationException(beanName,
                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                ex);
    }
}

  接触过 Spring 的都清楚,在 Spring 中存在着不同的 scope ,其中默认的是 singleton ,但是还有些其他的 scope 配置,如 prototye 、 request 、 session 等。在这个过程中,Spring 会根据不同的配置进行不同的初始化策略。详细的分析请参考:《Spring5源码分析(025)——IoC篇之bean加载:根据各种scope进行bean的实例化

 

2.9、类型转换

  对应的调用代码如下:
/// org.springframework.beans.factory.support.AbstractBeanFactory

// 9、类型转换 : 检查需要的类型是否符合 bean 的实际类型
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
    try {
        T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
        if (convertedBean == null) {
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
        return convertedBean;
    }
    catch (TypeMismatchException ex) {
        if (logger.isTraceEnabled()) {
            logger.trace("Failed to convert bean '" + name + "' to required type '" +
                    ClassUtils.getQualifiedName(requiredType) + "'", ex);
        }
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    }
}

  经过前面的处理,程序到这里返回 bean 后已经基本结束了。通常对该方法的调用参数 requiredType 都为 null ,也即是前面通过 getBean(String name) 的方式来获取,但是可能会存在这样的情况,返回的 bean 其实是个 String ,但是 requiredType 却传入 Integer 类型,那么这时候类型转换就会起作用了,它的功能就是将返回的 bean 转换成 requiredType 所指定的类型。当然,String 转换成 Integer 是最简单的一种转换,在 Spring 中提供了各种各样的转换器,用户也可以自己扩展转换器来满足自定义需求。

 
  经过以上步骤的处理后 bean 的加载就结束了,这个时候就可以返回所需要的 bean 了。其中比较重要的是步骤8,针对不同的 scope 进行 bean 的创建,我们将会看到各种常用的 Spring 特性在这里的实现。另外就是循环依赖的处理,这也是一个比较重要的知识点。后面将逐一对以上步骤进行详细的讲解。
 

3、参考

posted @ 2021-06-19 15:53  心明谭  阅读(154)  评论(0编辑  收藏  举报