[Spring]Spring的getBean路线-doGetBean

doGetBean的总体流程

  • 尝试从缓存中获取Bean.
  • 判断是否有循环依赖.
  • 判断能否从当前容器获取Bean,不能则递归从父容器中获取.
  • 合并BeanDefiniton,并检查BeanDefiniton,作为createBean的材料.
  • 根据声明的DependsOn去实例化需要提前实例化的Bean.
  • 根据不同的Scope:single、prototype、其他scope使用不同的创建Bean策略.
  • 对Bean做类型检查.

1. 尝试从缓存中获取Bean

    protected <T> T doGetBean(
            String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
            throws BeansException {
        // 返回Bean名称,必要时去除工厂取消引用前缀,并将别名解析为规范名称
        // 通过三种形式获取beanName.
        // 1. 原始的beanName.2. FactoryBean->&beanName. 3. alias
        String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        // 尝试从单例缓存集合中获取bean实例
        Object sharedInstance = getSingleton(beanName);
        // 省略....
}

要从缓存中获取Bean,首先要转换出真正的beanName.
我们注册在Spring中的Bean,其名称有三种形式:

  1. beanName.即Bean本身持有的名称,如UserDao这个Bean,Spring会自动为其生成"userDao".
  2. alias.别名,如果你想指定Bean的名称,可以在@Bean中指定该Bean的别名.示例: @Bean({"personC", "Kobe"})
  3. FactoryBean.容器工厂的Bean,对这类Bean会返回其实现类中的getObject对象.名称通常为"&beanName".
    Spring通过transformedBeanName来转换出beanName:
    如果是beanName,返回beanName.
    如果是别名,返回beanName.
    如果是FactoryBean,并且传入的beanName以("&beanName")的形式,返回beanName.
    当获取到beanName后,Spring尝试从缓存中获取bean实例.
  • DefaultSingletonBeanRegistry#getSingleton
    @Override
    @Nullable
    public Object getSingleton(String beanName) {
        // 第二个参数为是否允许立即加载,这里传入的是true
        return getSingleton(beanName, true);
    }

2. Spring的三级缓存

  • singletonObjects: 存储完整的Bean.
  • earlySingletonObjects: 半成品的Bean,未进行属性赋值.
  • singletonFactories: 提前暴露的对象实例,仅仅做了实例化,未具备属性.
    /** Cache of singleton objects: bean name to bean instance. */
    /** 一级缓存:单例对象缓存池,beanName->Bean,其中存储的是完整的Bean.*/
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of singleton factories: bean name to ObjectFactory.<br>
     *  三级缓存:单例工厂的缓存,beanName->ObjectFactory,添加进去的时候实例未具备属性.<br>
     *  用于保存beanName和创建Bean工厂之间的关系map,单例Bean在创建之初过早暴露出去的Factory.<br>
     *  为什么采用工厂方法,是因为有些Bean是需要被代理的,总不能把代理前的暴露出去那就毫无意义了.<br>
     * */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** Cache of early singleton objects: bean name to bean instance.<br>
     * 早期的单例对象,beanName->ObjectFactory,存储的是实例化后,属性未赋值的单例对象.<br>
     * 执行了工厂方法生产出来的bean被放进去之后.<br>
     * 那么当bean在创建过程中,就可以通过getBean方法获取到.<br>
     * */

    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

3.从三级缓存中获取对象实例

  • DefaultSingletonBeanRegistry#getSingleton
    /**
     * Return the (raw) singleton object registered under the given name.
     * <p>Checks already instantiated singletons and also allows for an early
     * reference to a currently created singleton (resolving a circular reference).<br>
     * 返回以给定名称注册的(原始)单例对象。<br>
     * 检查已经实例化的单例,并且还允许对当前创建的单例的早期引用(解析循环引用)。<br>
     * 单例对象只能存在三级缓存中的某一级,此处会尝试从一级、二级、三级中进行获取.<br>
     * @param beanName the name of the bean to look for
     * @param allowEarlyReference whether early references should be created or not
     * @return the registered singleton object, or {@code null} if none found
     */
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 尝试从一级缓存中获取完整的Bean
        Object singletonObject = this.singletonObjects.get(beanName);
        // 如果完整的单例Bean没有被创建出来,创建中的Bean的名字会被保存在singletonsCurrentlyInCreation中
        // 也就是说,当前所需要获取的bean是否是singleton的,并且处于创建中的形态
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            // 同步锁,开始对缓存对象进行操作.
            // 这里作为锁还有一个原因是二级缓存和三级缓存都是HashMap,需要一个锁来控制这两个map的操作
            synchronized (this.singletonObjects) {
                // 尝试从二级缓存earlySingletonObjects中获取半成品的Bean。
                // 二级缓存存储的是未对属性进行添加的Bean.
                singletonObject = this.earlySingletonObjects.get(beanName);
                // 如果还获取不到,并且allowEarlyReference为true,则表示可以进行循环引用
                if (singletonObject == null && allowEarlyReference) {
                    // 从三级缓存singletonFactories这个ObjectFactory实例的缓存中尝试获取创建此Bean的单例工厂实例
                    // ObjectFactory为用户定制(容器中的代理Bean),FactoryBean框架会进行特殊处理(自定义)
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        // 调用单例工厂的getObject方法获取对象实例
                        singletonObject = singletonFactory.getObject();
                        // 将实例放入二级缓存中.
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        // 从三级缓存中删除
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }

Spring默认支持循环依赖,在这个getSingleton()中,根据beanName去一级、二级、三级缓存中进行查找:

  1. 尝试从一级缓存中查找完整的Bean实例,找到则直接返回.
  2. 如果无法从一级缓存中查找,对一级缓存进行上锁,然后尝试从二级缓存中查找半成品的Bean.找到直接返回.
  3. 从三级缓存中查找,找到则放入二级缓存,同时为了保证一个对象实例为单例,将该实例从第三级缓存中进行移除.

4. 检测循环依赖.

protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
        throws BeansException {
    // 省略若干代码....
    
    // 尝试从单例缓存集合中获取bean实例
    Object sharedInstance = getSingleton(beanName);
    // 如果之前已经创建过该单例bean,并且args为空(单例 bean不可以用这个args,它是为多例设计的)
    if (sharedInstance != null && args == null) {
        if (logger.isTraceEnabled()) {
            // 如果Bean还在创建中,则说明是循环依赖.
            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 + "'");
            }
        }
        // 如果是普通的bean,直接返回,如果是factoryBean,则返回它的getObject.
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    
    // 省略若干代码....
}

尝试从缓存中获取对象实例后,如果该共享对象实例不为空且参数为空,那么进行循环依赖的检测:
1.如果该beanName出现在singletonsCurrentlyInCreation中,那么证明是循环依赖.
2.否则为缓存的Bean实例.
通过getObjectForBeanInstance返回对象实例.该方法会判断bean是否为FactoryBean,则通过其getObject获取Bean实例:
在访问FactoryBean的过程中,先从FactoryBean缓存中获取(单例模式下,仅存在一个FactoryBean),如果没有则调用其getObject方法,此处Spring使用了双重检测锁机制来创建FactoryBean.值得一读.

    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        if (factory.isSingleton() && containsSingleton(beanName)) {
            // 上同步锁
            synchronized (getSingletonMutex()) {
                // 双重检测锁机制,先从缓存中获取,多线程下可能别的线程已完成该单例Bean的创建.
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    // 调用getObject工厂方法创建Bean实例
                    object = doGetObjectFromFactoryBean(factory, beanName);
                    // Only post-process and store if not put there already during getObject() call above
                    // (e.g. because of circular reference processing triggered by custom getBean calls)
                    // 如果在getObject期间别的线程异步进行了bean的创建,那么使用更早的版本,以保证单例
                    // 为什么出现两次从缓存读取的操作,因为用户自定义的getObject可能会出现异步,所以这里需要再进行一次判断
                    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                    if (alreadyThere != null) {
                        object = alreadyThere;
                    }
                    else {
                        // Spring的内部类不会进入到这个方法,因为Spring不允许第三方框架通过后置处理器更改其内部类
                        if (shouldPostProcess) {
                            // 该Bean实例是否有别的线程在尝试创建,但是未进行后置处理
                            if (isSingletonCurrentlyInCreation(beanName)) {
                                // Temporarily return non-post-processed object, not storing it yet..
                                return object;
                            }
                            // 后置处理完成前,先加入缓存中锁定起来
                            beforeSingletonCreation(beanName);
                            try {
                                // 触发BeanPostProcessor.第三方框架可以使用AOP来包装Bean实例
                                // 对Bean实施创建上的后置处理
                                object = postProcessObjectFromFactoryBean(object, beanName);
                            }
                            catch (Throwable ex) {
                                throw new BeanCreationException(beanName,
                                        "Post-processing of FactoryBean's singleton object failed", ex);
                            }
                            finally {
                                // 锁定解除
                                afterSingletonCreation(beanName);
                            }
                        }
                        if (containsSingleton(beanName)) {
                            // 放入缓存中,证明单例已经创建完成了.
                            this.factoryBeanObjectCache.put(beanName, object);
                        }
                    }
                }
                return object;
            }
        }
        else {
            // 非单例直接getObject
            Object object = doGetObjectFromFactoryBean(factory, beanName);
            if (shouldPostProcess) {
                try {
                    object = postProcessObjectFromFactoryBean(object, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
                }
            }
            return object;
        }
    }

5.如果从缓存中获取不到Bean实例,开始着手创建Bean.

// 如果scope->prototype,singleton.但是在缓存中无法找到
        else {
            // Fail if we're already creating this bean instance:
            // We're assumably within a circular reference.
            // 如果scope为prototype并且仍然处于创建的状态,那么可以认为是处于循环依赖中了.
            // 针对prototype的循环依赖,spring无法解决,此处会抛出异常
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

            // Check if bean definition exists in this factory.
            BeanFactory parentBeanFactory = getParentBeanFactory();
            // 如果在当前容器中无法找到指定名称的bean,此时递归去parentFactory查找.
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                // Not found -> check parent.
                // 针对FactoryBean,将Bean的&重新拼上
                String nameToLookup = originalBeanName(name);
                // 如果parentBeanFactory属于AbstractBeanFactory实例
                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.
                    // 如果没有参数,委托父级容器根据指定名称和type进行查找
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
                else {
                    // 委派父级容器根据指定名称查找.
                    return (T) parentBeanFactory.getBean(nameToLookup);
                }
            }

            if (!typeCheckOnly) {
                // 如果不是仅仅做类型检测则创建bean
                markBeanAsCreated(beanName);
            }

            try {
                // 将父类的BeanDefinition与子类的BeanDefinition进行合并覆盖
                RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                // 对合并的BeanDefiniton进行检测,主要判断是否为abstract.
                checkMergedBeanDefinition(mbd, beanName, args);

                // Guarantee initialization of beans that the current bean depends on.
                // 获取当前Bean所有依赖的Bean名称
                String[] dependsOn = mbd.getDependsOn();
                // 如果当前Bean设置了dependsOn的属性(用来指定Bean初始化即销毁时的顺序)
                // <bean id = A ,Class = "xxx.xxx.A" depends-on = "B">
                // <bean id = B ,Class = "xxx.xxx.B">
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        // 检测该依赖是否已经注册给当前Bean
                        // A-dependsOn-B
                        // B-dependsOn-A
                        // 如果是这种情况,直接抛出异常
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        // 缓存依赖调用,dep->被依赖的beanName
                        registerDependentBean(dep, beanName);
                        try {
                            // 递归调用getBean,注册Bean之间的依赖(C->B->A)
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }

                // Create bean instance.
                // 如果BeanDefiniton为单例
                if (mbd.isSingleton()) {
                    // 匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
                    // 关键方法:单例类实例化的入口
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            // 创建单例bean的入口.
                            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 = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
  1. 在真正的创建单例Bean之前,Spring会先检查当前beanName是否在prototypesCurrentlyInCreation中,prototypesCurrentlyInCreation是一个ThreadLocal的Set集合,其中存储了当前正在创建的多例BeanName集合,Spring不支持prototye作用域的循环依赖,所以会抛出一个BeanCurrentlyInCreationException.
  2. 向上递归获取父容器,尝试找到该beanName的对象实例.这里有点像类加载时的双亲委派机制去加载bean.
  3. 检查是否为类型检查,如果不仅仅是类型检查,那么Spring知晓为创建Bean了,会开始在一个alreadyCreated的Set集合中加入该BeanName的名称.这里会存储已经创建好的或者正在创建中的beanName.并且进行clearMergedBeanDefinition操作。
  4. 如果从父容器无法获取,开始进行进行创建Bean之前的一些准备工作,例如getMergedLocalBeanDefinition,检测当前的RootBeanDefinition是否为abstract的.同时,如果bean声明了dependsOn,还会进行相应的注册逻辑,同时递归调用getBean方法进行Bean的初始化.
    注意:dependsOn是不可以有循环声明的.因为dependsOn显示声明了Bean创建的顺序,如果还存在循环声明,就会乱套.
  5. 经过上面的校验后,如果Bean的作用域为singleton,就开始进行createBean操作了.此处Spring是调用了一个重载的getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法.而createBean作为ObjectFactory这个函数式接口的代码块进行了传递.在这个getSingleton中,Spring会调用传进来的singletonFactory.getObject()方法,实际上,就是调用的createBean.
  • DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory)
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        // 上同步锁
        synchronized (this.singletonObjects) {
            // 从一级缓存中获取Bean实例
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                // 如果当前容器正在当前Bean进行销毁,则直接抛出异常
                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 + "'");
                }
                // 查看当前bean是否可以进行加载
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                try {
                    // 传入的lambda代码块逻辑在这里执行.
                    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;
                    }
                    // 从singletonsCurrentlyInCreation中移除当前beanName的信息,因为已经完成了bean的创建了
                    afterSingletonCreation(beanName);
                }
                // 如果创建了一个新的单例Bean,将其添加到一级缓存中.
                // 同时为了保证一个单例Bean只出现一次,将其从二级、三级缓存中进行移除
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }
  1. 如果当前bean的scope为prototype,直接进行createBean,原型模式下,每次getBean都会创建新的对象实例.
                else if (mbd.isPrototype()) {
                    // It's a prototype -> create a new instance.
                    // 如果是原型模式,创建一个实例,在原型模式下,每次getBean都会产生一个新的实例
                    Object prototypeInstance = null;
                    try {
                        // 将当前创建的Bean标记为创建中
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        // 完成创建后,从prototypesCurrentlyInCreation移除beanName
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }

7.如果bean的scope不是singletonprototype,则调用scope.get()来选择合适的加载策略.
8.做类型校验,这里不做重点的阐述.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容