Spring IOC源码解析-获取单例bean

一.简介

假设当前IOC容器已经载入用户定义的Bean信息,开始分析依赖注入的原理。首先,注意到依赖注入的过程是用户第一次向IOC容器索要Bean时触发的,当然也有例外,也就是我们可以在BeanDefinition信息中通过控制lazy-init属性来让容器完成对Bean的预实例化。这个预实例化过程实际上也是一个完成依赖出入的过程,但是它在初始化的过程中完成的(这个部分在这篇文章中就不详细讲述了)。当用户向IOC索要Bean的时,在基本IOC容器接口BeanFactory中,有一个getBean的接口定义,这个接口的实现就是触发依赖注入的地方。下面从DefaultListableBeanFactory的基类AbstractBeanFactory去看getBean的实现,但是并没有关注其中调用的方法。

二.源码分析

2.1 getBean(String)源码

public Object getBean(String name) throws BeansException {
    // getBean 是一个空壳方法,所有的逻辑都封装在 doGetBean 方法中
    return doGetBean(name, null, null, false);
}

protected  T doGetBean(
        final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {

    // 1.
    /*
     * 通过 name 获取 beanName。这里不使用 name 直接作为 beanName 有两点原因:
     * 1. name 可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身,而非 FactoryBean 
     *    实现类所创建的 bean。在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储
     *    方式是一致的,即 ,beanName 中是没有 & 这个字符的。所以我们需要
     *    将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例。
     * 2. 若 name 是一个别名,则应将别名转换为具体的实例名,也就是 beanName。
     */
    final String beanName = transformedBeanName(name);
    Object bean;

   
    //2.
    /*
     * 从缓存中获取单例 bean。Spring 是使用 Map 作为 beanName 和 bean 实例的缓存的,所以这
     * 里暂时可以把 getSingleton(beanName) 等价于 beanMap.get(beanName)。当然,实际的
     * 逻辑并非如此简单,后面再细说。
     */
    Object sharedInstance = getSingleton(beanName);

    /*
     * 如果 sharedInstance = null,则说明缓存里没有对应的实例,表明这个实例还没创建。
     * BeanFactory 并不会在一开始就将所有的单例 bean 实例化好,而是在调用 getBean 获取 
     * bean 时再实例化,也就是懒加载。
     * getBean 方法有很多重载,比如 getBean(String name, Object... args),我们在首次获取
     * 某个 bean 时,可以传入用于初始化 bean 的参数数组(args),BeanFactory 会根据这些参数
     * 去匹配合适的构造方法构造 bean 实例。当然,如果单例 bean 早已创建好,这里的 args 就没有
     * 用了,BeanFactory 不会多次实例化单例 bean。
     */
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
      
       
     //3.
        /*
         * 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果 
         * sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的 
         * bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
         * 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
         */
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
   //4.
    /*
     * 如果上面的条件不满足,则表明 sharedInstance 可能为空,此时 beanName 对应的 bean 
     * 实例可能还未创建。这里还存在另一种可能,如果当前容器有父容器,beanName 对应的 bean 实例
     * 可能是在父容器中被创建了,所以在创建实例前,需要先去父容器里检查一下。
     */
    else {
        // BeanFactory 不缓存 Prototype 类型的 bean,无法处理该类型 bean 的循环依赖问题
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        //5.
        // 如果 sharedInstance = null,则到父容器中查找 bean 实例
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // 获取 name 对应的 beanName,如果 name 是以 & 字符开头,则返回 & + beanName
            String nameToLookup = originalBeanName(name);
            // 根据 args 是否为空,以决定调用父容器哪个方法获取 bean
            if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            } 
            else {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }

        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
             //6.
            // 合并父 BeanDefinition 与子 BeanDefinition,后面会单独分析这个方法
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);
       
  
             //7.
            // 检查是否有 dependsOn 依赖,如果有则先初始化所依赖的 bean
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    /*
                     * 检测是否存在 depends-on 循环依赖,若存在则抛异常。比如 A 依赖 B,
                     * B 又依赖 A,他们的配置如下:
                     *   
                     *   
                     *   
                     * beanA 要求 beanB 在其之前被创建,但 beanB 又要求 beanA 先于它
                     * 创建。这个时候形成了循环,对于 depends-on 循环,Spring 会直接
                     * 抛出异常
                     */
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 注册依赖记录
                    registerDependentBean(dep, beanName);
                    try {
                        // 加载 depends-on 依赖
                        getBean(dep);
                    } 
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }
            //8.
            // 创建 bean 实例
            if (mbd.isSingleton()) {
                /*
                 * 这里并没有直接调用 createBean 方法创建 bean 实例,而是通过 
                 * getSingleton(String, ObjectFactory) 方法获取 bean 实例。
                 * getSingleton(String, ObjectFactory) 方法会在内部调用 
                 * ObjectFactory 的 getObject() 方法创建 bean,并会在创建完成后,
                 * 将 bean 放入缓存中。关于 getSingleton 方法的分析,本文先不展开,我会在
                 * 后面的文章中进行分析
                 */
                sharedInstance = getSingleton(beanName, new ObjectFactory() {
                    @Override
                    public Object getObject() throws BeansException {
                        try {
                            // 创建 bean 实例
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    }
                });
                // 如果 bean 是 FactoryBean 类型,则调用工厂方法获取真正的 bean 实例。否则直接返回 bean 实例
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            // 创建 prototype 类型的 bean 实例
            else if (mbd.isPrototype()) {
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            // 创建其他类型的 bean 实例
            else {
                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 {
                    Object scopedInstance = scope.get(beanName, new ObjectFactory() {
                        @Override
                        public Object getObject() throws BeansException {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    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.
    // 如果需要进行类型转换,则在此处进行转换。类型转换这一块我没细看,就不多说了。
    if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
        try {
            return getTypeConverter().convertIfNecessary(bean, requiredType);
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }

    // 返回 bean
    return (T) bean;
} 
  

doGetBean的工作流程如下:

1.转换对应的beanName。

2.尝试从缓存中加载单例。单例在Spring的同一个容器中只会被创建一次,后续在获取单例,就直接从单例缓存中获取。当然这里的也只是尝试加载,首先尝试从缓存中加载,如果加载不成功则再次从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring创建bean的原则是不等bean创建完成后就会将创建bean的ObjectFactory提前曝光加入到缓存中,一旦下一个bean创建的时候需要依赖上一个bean则直接使用ObjectFactory(后面会详细讲解循环依赖)。

3.bean的实例化。如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。缓存中记录的只是最原始的bean的状态,并不一定使我们最终想要的bean。举个例子,假如我们需要对工厂bean进行处理,那么这里得到的其实就是工厂bean的初始状态,但实际需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance就是完成这个工作的,后面会详细讲解。

4.原型模式的依赖检查。只有单例情况下才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为对B的创建再次返回创建A,造成循环依赖,也就是情况:isPrototypeCurrentInCreation(beanName)判断为true。

5.检测parentBeanFactory。

6.将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition。因为从XML配置文件读取的Bean信息存储在GernericBeanDefinition,但是所有Bean后续处理都是针对于RootBeanDefinition的,所以这里需要进行一个转换,转换的同时,如果父类bean不为空的话,则会一并合并父类的属性。

7.寻找依赖。

8.针对不同的scope进行bean的创建。

9.类型转换。

以上步骤对应的流程图如下:

Spring IOC源码解析-获取单例bean_第1张图片

2.2 beanName转换

在获取bean实例之前,String第一件要做的事情就是对参数name进行转换。转换的目的主要是为了解决两个问题,第一个问题是处理字符&开头的name,防止BeanFactory无法找到与name对应的bean实例。第二个是处理别名问题,Spring不会存储<别名,bean实例>这种映射,仅会存储。所以,同样是为了避免BeanFactory找不到name对应的bean的实例,对于别名也要进行转换。下来,对转换过程进行分析,如下:

protected String transformedBeanName(String name) {
    // 这里调用了两个方法:BeanFactoryUtils.transformedBeanName(name) 和 canonicalName
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

/** 该方法用于处理 & 字符 */
public static String transformedBeanName(String name) {
    Assert.notNull(name, "'name' must not be null");
    String beanName = name;
    // 循环处理 & 字符。比如 name = "&&&&&helloService",最终会被转成 helloService
    while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
        beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
    }
    return beanName;
}

/** 该方法用于转换别名 */
public String canonicalName(String name) {
    String canonicalName = name;
    String resolvedName;
    /*
     * 这里使用 while 循环进行处理,原因是:可能会存在多重别名的问题,即别名指向别名。比如下面
     * 的配置:
     *   
     *   
     *   
     *
     * 上面的别名指向关系为 aliasB -> aliasA -> hello,对于上面的别名配置,aliasMap 中数据
     * 视图为:aliasMap = [, ]。通过下面的循环解析别名
     * aliasB 最终指向的 beanName
     */
    do {
        resolvedName = this.aliasMap.get(canonicalName);
        if (resolvedName != null) {
                canonicalName = resolvedName;
        }
    }
    while (resolvedName != null);
    return canonicalName;
}

2.3 从缓存中获取bean实例

对于单例bean,Spring容器只会实例化一次。后面再次获取时,只需要从缓存里获取即可,无需且不能再次实例化。从缓存取bean实例的方法是getSingleton(String),下来对这个方法进行分析:

public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

/**
 * 这里解释一下 allowEarlyReference 参数,allowEarlyReference 表示是否允许其他 bean 引用
 * 正在创建中的 bean,用于处理循环引用的问题。关于循环引用,这里先简单介绍一下。先看下面的配置:
 *
 *   
 *       
 *   
 *   
 *       
 *   
 * 
 * 如上所示,hello 依赖 world,world 又依赖于 hello,他们之间形成了循环依赖。Spring 在构建 
 * hello 这个 bean 时,会检测到它依赖于 world,于是先去实例化 world。实例化 world 时,发现 
 * world 依赖 hello。这个时候容器又要去初始化 hello。由于 hello 已经在初始化进程中了,为了让 
 * world 能完成初始化,这里先让 world 引用正在初始化中的 hello。world 初始化完成后,hello 
 * 就可引用到 world 实例,这样 hello 也就能完成初始了。关于循环依赖,我后面会专门写一篇文章讲
 * 解,这里先说这么多。
 */
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从 singletonObjects 获取实例,singletonObjects 中缓存的实例都是完全实例化好的 bean,可以直接使用
    Object singletonObject = this.singletonObjects.get(beanName);
    /*
     * 如果 singletonObject = null,表明还没创建,或者还没完全创建好。
     * 这里判断 beanName 对应的 bean 是否正在创建中
     */
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 从 earlySingletonObjects 中获取提前曝光的 bean,用于处理循环引用
            singletonObject = this.earlySingletonObjects.get(beanName);
            // 如果如果 singletonObject = null,且允许提前曝光 bean 实例,则从相应的 ObjectFactory 获取一个原始的(raw)bean(尚未填充属性)
            if (singletonObject == null && allowEarlyReference) {
                // 获取相应的工厂类
                ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 提前曝光 bean 实例,用于解决循环依赖
                    singletonObject = singletonFactory.getObject();
                    // 放入缓存中,如果还有其他 bean 依赖当前 bean,其他 bean 可以直接从 earlySingletonObjects 取结果
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

这个方法首先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject来创建bean,并放到earlySingletonObjects里面去,并且从singletonFactories里面remove掉这个ObjectFactory,对于后续的所有内存操作都只是为了循环依赖检测时候使用,也就是allowEarlyReference为true的情况下使用。(这个后面解决循环依赖的时候会讲到)

这里涉及用于存储bean的不同的map,简单解释下:

  • singletonObjects:用于存放完全初始化好的bean,从该缓存中取出的bean可以直接使用。
  • earlySingletonObjects:用于存放还在初始化的bean,用于解决循环依赖
  • singletonFactories:用于存放bean工厂。bean工厂所产生的bean时还未初始化的bean,如代码所示,bean工厂所生成的对象最终会被缓存到earlySingletonObjects中。

2.4 合并父BeanDefinition和子BeanDefinition

我们知道,Spring支持配置继承,在标签中可以使用parent属性配置父类bean。这样子类bean可以继承父类bean的配置信息,同时也可以覆盖父类中的配置。

源码分析如下:

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    // 检查缓存中是否存在“已合并的 BeanDefinition”,若有直接返回即可
    RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
    if (mbd != null) {
        return mbd;
    }
    // 调用重载方法
    return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
        throws BeanDefinitionStoreException {
    // 继续调用重载方法
    return getMergedBeanDefinition(beanName, bd, null);
}

protected RootBeanDefinition getMergedBeanDefinition(
        String beanName, BeanDefinition bd, BeanDefinition containingBd)
        throws BeanDefinitionStoreException {

    synchronized (this.mergedBeanDefinitions) {
        RootBeanDefinition mbd = null;

        if (containingBd == null) {
            mbd = this.mergedBeanDefinitions.get(beanName);
        }

        if (mbd == null) {
            // bd.getParentName() == null,表明无父配置,这时直接将当前的 BeanDefinition 升级为 RootBeanDefinition
            if (bd.getParentName() == null) {
                if (bd instanceof RootBeanDefinition) {
                    mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
                }
                else {
                    mbd = new RootBeanDefinition(bd);
                }
            }
            else {
                BeanDefinition pbd;
                try {
                    String parentBeanName = transformedBeanName(bd.getParentName());
                    /*
                     * 判断父类 beanName 与子类 beanName 名称是否相同。若相同,则父类 bean 一定
                     * 在父容器中。原因也很简单,容器底层是用 Map 缓存  键值对
                     * 的。同一个容器下,使用同一个 beanName 映射两个 bean 实例显然是不合适的。
                     * 有的朋友可能会觉得可以这样存储: ,似乎解决了
                     * 一对多的问题。但是也有问题,调用 getName(beanName) 时,到底返回哪个 bean 
                     * 实例好呢?
                     */
                    if (!beanName.equals(parentBeanName)) {
                        /*
                         * 这里再次调用 getMergedBeanDefinition,只不过参数值变为了 
                         * parentBeanName,用于合并父 BeanDefinition 和爷爷辈的 
                         * BeanDefinition。如果爷爷辈的 BeanDefinition 仍有父 
                         * BeanDefinition,则继续合并
                         */
                        pbd = getMergedBeanDefinition(parentBeanName);
                    }
                    else {
                        // 获取父容器,并判断,父容器的类型,若不是 ConfigurableBeanFactory 则判抛出异常
                        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);
                }
                // 以父 BeanDefinition 的配置信息为蓝本创建 RootBeanDefinition,也就是“已合并的 BeanDefinition”
                mbd = new RootBeanDefinition(pbd);
                // 用子 BeanDefinition 中的属性覆盖父 BeanDefinition 中的属性
                mbd.overrideFrom(bd);
            }

            // 如果用户未配置 scope 属性,则默认将该属性配置为 singleton
            if (!StringUtils.hasLength(mbd.getScope())) {
                mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
            }

            if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
                mbd.setScope(containingBd.getScope());
            }

            if (containingBd == null && isCacheBeanMetadata()) {
                // 缓存合并后的 BeanDefinition
                this.mergedBeanDefinitions.put(beanName, mbd);
            }
        }

        return mbd;
    }
}

2.5 获取单例

上面的getSingleton方法是从缓存中获取单例的过程,那么如果缓存中不存在已经加载的单例bean,就需要从头开始bean的加载过程了,而Spring中使用getSingleton的重载方法实现bean的加载过程。

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) {
            if (this.singletonsCurrentlyInDestruction) {
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                        "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
            beforeSingletonCreation(beanName);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    throw ex;
                }
            }
            catch (BeanCreationException ex) {
                if (recordSuppressedExceptions) {
                    for (Exception suppressedException : this.suppressedExceptions) {
                        ex.addRelatedCause(suppressedException);
                    }
                }
                throw ex;
            }
            finally {
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = null;
                }
                afterSingletonCreation(beanName);
            }
            if (newSingleton) {
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

上述的代码其实使用了回调方法,使得程序可以在单例创建前后可以做一些准备以及处理操作,而真正的获取单例bean的方法其实不是在此方法中实现的,其实现逻辑实在ObjectFactory类型的实例singletonFactory中实现的。而这些准备及处理操作包含以下内容:

1.检查缓存是否已经加载过

2.若没有加载,则记录该beanName的正在加载状态

3.加载单例前记录加载状态,也就是通过beforeSingletonCreation(beanName)方法记录加载状态

4.通过调用参数传入的ObjectFactory的个体Object方法实例化bean

5.加载单例后的处理方法调用,通过afterSingletonCreation(beanName)方法移除缓存中对该bean的正在加载状态的记录

6.通过 addSingleton(beanName, singletonObject)将结果记录至缓存并删除加载bean过程中所记录的各种辅助状态。

7.返回处理结果

2.6 从FactoryBean中获取bean实例

在getBean方法中,getObjectForBeanInstance是一个高频率使用的方法,无论是从缓存中获得bean还是根据不同的scope策略加载bean。总之,我们得到的bean实例后要做的第一步就是调用这个方法检测一下正确性,其实就是检测当前的bean是否是FactoryBean类型的bean,如果是,那么需要调用该bean对应的FactoryBean实例中getObject()作为返回值。

无论从缓存中获得到的bean还是通过不同scope策略加载的bean都只是最原始的bean状态,并不是我们最终想要的那个bean。举个例子,假设我们需要对工厂bean进行处理,那么这里得到的其实是bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance方法就是完成这个工作的。

protected Object getObjectForBeanInstance(
        Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

    // 如果 name 以 & 开头,但 beanInstance 却不是 FactoryBean,则认为有问题。
    if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
        throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
    }

    /* 
     * 如果上面的判断通过了,表明 beanInstance 可能是一个普通的 bean,也可能是一个 
     * FactoryBean。如果是一个普通的 bean,这里直接返回 beanInstance 即可。如果是 
     * FactoryBean,则要调用工厂方法生成一个 bean 实例。
     */
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }

    Object object = null;
    if (mbd == null) {
        /*
         * 如果 mbd 为空,则从缓存中加载 bean。FactoryBean 生成的单例 bean 会被缓存
         * 在 factoryBeanObjectCache 集合中,不用每次都创建
         */
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // 经过前面的判断,到这里可以保证 beanInstance 是 FactoryBean 类型的,所以可以进行类型转换
        FactoryBean factory = (FactoryBean) beanInstance;
        // 如果 mbd 为空,则判断是否存在名字为 beanName 的 BeanDefinition
        if (mbd == null && containsBeanDefinition(beanName)) {
            // 合并 BeanDefinition
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());

        // 调用 getObjectFromFactoryBean 方法继续获取实例
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

getObjectForBeanInstance中要做的工作:

1.对FactoryBean正确性的验证。

2.对非FactoryBean不做任何处理。

3.对bean进行转换。

4.将从Factory中解析bean的工作委托给getObjectFormFactoryBean。

getObjectFormFactoryBean源码如下:

protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
    /*
     * FactoryBean 也有单例和非单例之分,针对不同类型的 FactoryBean,这里有两种处理方式:
     *   1. 单例 FactoryBean 生成的 bean 实例也认为是单例类型。需放入缓存中,供后续重复使用
     *   2. 非单例 FactoryBean 生成的 bean 实例则不会被放入缓存中,每次都会创建新的实例
     */
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            // 从缓存中取 bean 实例,避免多次创建 bean 实例
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                // 使用工厂对象中创建实例
                object = doGetObjectFromFactoryBean(factory, beanName);
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                }
                else {
                    // shouldPostProcess 等价于上一个方法中的 !synthetic,用于表示是否应用后置处理
                    if (object != null && shouldPostProcess) {
                        if (isSingletonCurrentlyInCreation(beanName)) {
                            return object;
                        }
                        beforeSingletonCreation(beanName);
                        try {
                            // 应用后置处理
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                        finally {
                            afterSingletonCreation(beanName);
                        }
                    }
                    // 这里的 beanName 对应于 FactoryBean 的实现类, FactoryBean 的实现类也会被实例化,并被缓存在 singletonObjects 中
                    if (containsSingleton(beanName)) {
                        // FactoryBean 所创建的实例会被缓存在 factoryBeanObjectCache 中,供后续调用使用
                        this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
                    }
                }
            }
            return (object != NULL_OBJECT ? object : null);
        }
    }
    // 获取非单例实例
    else {
        // 从工厂类中获取实例
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (object != null && shouldPostProcess) {
            try {
                // 应用后置处理
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

在这个方法里只做了一件事情,就是返回的bean如果是单例的,那就必须保证全局唯一,同时,也因为是单例的,所以不必重复创建,可以使用缓存来提高性能,也就是说已经加载过就要就要记录下来以便下次复用,否则的话,直接获取了。

doGetObjectFromFactoryBean方法解析:

private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName)
        throws BeanCreationException {

    Object object;
    try {
        // if 分支的逻辑是 Java 安全方面的代码,可以忽略,直接看 else 分支的代码
        if (System.getSecurityManager() != null) {
            AccessControlContext acc = getAccessControlContext();
            try {
                object = AccessController.doPrivileged(new PrivilegedExceptionAction() {
                    @Override
                    public Object run() throws Exception {
                            return factory.getObject();
                        }
                    }, acc);
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            // 调用工厂方法生成 bean 实例
            object = factory.getObject();
        }
    }
    catch (FactoryBeanNotInitializedException ex) {
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    }

    if (object == null && isSingletonCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(
                beanName, "FactoryBean which is currently in creation returned null from getObject");
    }
    return object;
} 
  

如果bean声明为FactoryBean类型,则当提取bean时提取的不是FactoryBean,而是FactoryBean对应的getObject方法返回的bean,而doGetObjectFromFactoryBean正是实现这个功能的。

得到了返回结果并没有直接返回,又做了后处理的操作,这个在后面会解析到。

getObjectForBeanInstance及它所调用的方法主要做了如下几件事情:

1.检测参数beanInstance的类型,如果是非FactoryBean类型的bean,直接返回

2.检测FactoryBean实现类是否单例类型,针对单例和非单例进行不同处理

3.对于单例FactoryBean,先从缓存中获取FactoryBean生成的实例

4.若缓存未命中,则调用FactoryBean.getObject()方法生成实例,并放入缓存中

5.对于非单例的FactoryBean,每次直接创建新的实例,无需缓存

6.如果shouldPostProcess=true,不管是单例还是非单例FactoryBean生成的实例,都要进行后置处理。

 

本文参考:Spring IOC 容器源码分析 - 获取单例 bean

                  《Spring源码深度解析》

你可能感兴趣的:(Spring)