AbstractBeanFactory#getBean(beanName)

由于 getBean 内容比较多, 所以单独出来, 接着上一篇的顺序来看.

复制代码

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

@Override

public Object getBean(String name) throws BeansException {

    return doGetBean(name, null, null, false);

}

复制代码

doGetBean里面, 有一堆乱七八糟的判断,

复制代码

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,

        @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    /**

    * 通过 name 获取 beanName。这里不使用 name 直接作为 beanName 有两个原因

    * 1、name 可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身,而非 FactoryBean

    *  实现类所创建的 bean。在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储

    *  方式是一致的,即 <beanName, bean>,beanName 中是没有 & 这个字符的。所以我们需要

    *  将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例。

    * 2、还是别名的问题,转换需要

    * &beanName

    */

    final String beanName = transformedBeanName(name);

    Object bean;

    // Eagerly check singleton cache for manually registered singletons.

    /**

    * 这个方法在初始化的时候会调用,在getBean的时候也会调用

    * 为什么需要这么做呢?

    * 也就是说spring在初始化的时候先获取这个对象

    * 判断这个对象是否被实例化好了(普通情况下绝对为空====初始化完之后, 此处返回就不是空了)

    * 从spring的bean容器中获取一个bean,由于spring中bean容器是一个map(singletonObjects)

    * 所以你可以理解getSingleton(beanName)等于beanMap.get(beanName)

    * 由于方法会在spring环境初始化的时候(就是对象被创建的时候调用一次)调用一次

    * 还会在getBean的时候调用一次

    *

    * 需要说明的是在初始化时候调用一般都是返回null

    */

    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 + "'");

            }

        }

        /**

        * 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。

        * 但如果 sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的 bean 实例。

        * 如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回即可。

        * 毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。

        */

        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);

    }

    else {

        // Fail if we're already creating this bean instance:

        // We're assumably within a circular reference.

        /**

        * 原型模式

        * 如果是原型不应该在初始化的时候创建

        */

        if (isPrototypeCurrentlyInCreation(beanName)) {

            throw new BeanCurrentlyInCreationException(beanName);

        }

        // Check if bean definition exists in this factory.

        BeanFactory parentBeanFactory = getParentBeanFactory();

        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {

          ......

        }

        if (!typeCheckOnly) {

            //添加到 alreadyCreated set集合当中,表示他已经创建过一场

            markBeanAsCreated(beanName);

        }

        try {

            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

            //bd检测, 如果是 abstract, 则抛异常

            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.

            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 {

                        getBean(dep);

                    }

                    catch (NoSuchBeanDefinitionException ex) {

                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,

                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);

                    }

                }

            }

            // Create bean instance.

            // 单例创建

            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.

                        destroySingleton(beanName);

                        throw ex;

                    }

                });

                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

            }

            else if (mbd.isPrototype()) {

                ......

            }

            else {

                ......

            }

        }

        catch (BeansException ex) {

            cleanupAfterBeanCreationFailure(beanName);

            throw ex;

        }

    }

    // Check if required type matches the type of the actual bean instance.

    if (requiredType != null && !requiredType.isInstance(bean)) {

        ......

    }

    return (T) bean;

}

复制代码

方法比较长, 我删掉一部分. 不影响观看.

主要看两个方法 :

1.getSingleton(String beanName, ObjectFactory<?> singetonFactory)

2.createBean

getSingleton

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton

复制代码

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 + "'");

            }

            /**

            * 将beanName添加到singletonsCurrentlyInCreation这样一个set集合中

            * 表示beanName对应的bean正在创建中

            */

            beforeSingletonCreation(beanName);

            boolean newSingleton = false;

            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);

            if (recordSuppressedExceptions) {

                this.suppressedExceptions = new LinkedHashSet<>();

            }

            try {

                //这里会调用传入的 lambda 表达式创建的匿名 singletonFactory 对象, 调用他的 getObject() 方法

                //其方法内部, 也就是调用 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean 方法

                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;

    }

}

复制代码

这里的getSingleton , 明显是一个创建 bean 的地方.

1. 在创建之前, 通过 beforeSingletonCreation() 方法, 执行了  this.singletonsCurrentlyInCreation.add(beanName) 这句代码,

这里其实是在做一个标志, 表示 这个 beanName 对应的 bean 正在创建当中. 将 singletonsCurrentlyInCreation 翻译过来, 就能看懂.

这里做到了变量名的命名就是最好的注释.

2. 调用 factory.getObject 方法, 进行 bean 的创建, 调用的其实就是 createBean() 方法.

3. 创建完成之后, 通过 afterSingletonCreation() 方法, 将标志位改回去, 其内部执行了 this.singletonsCurrentlyInCreation.remove(beanName) 这句代码.

4. 在最后, 通过 addSingleton() 方法, 将创建的 bean 放到 spring 容器中 : this.singletonObjects.put(beanName, singletonObject)

这里的这个顺序很重要, 尤其是那个 正在创建的标志, 很重要的 : singletonsCurrentlyInCreation

这个正在创建的标志, 在解决 循环依赖的时候, 起了很重要的作用

createBean

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean

复制代码

@Override

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

        throws BeanCreationException {

    if (logger.isTraceEnabled()) {

        logger.trace("Creating instance of bean '" + beanName + "'");

    }

    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point, and

    // clone the bean definition in case of a dynamically resolved Class

    // which cannot be stored in the shared merged bean definition.

    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {

        mbdToUse = new RootBeanDefinition(mbd);

        mbdToUse.setBeanClass(resolvedClass);

    }

    //Prepare method overrides.

    //处理xml中的 lookup-method 和 replace-method 配置,Spring将这两个配置统称为override method

    try {

        mbdToUse.prepareMethodOverrides();

    }

    catch (BeanDefinitionValidationException ex) {

        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),

                beanName, "Validation of method overrides failed", ex);

    }

    try {

        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.

        // 在 bean实例化之前 应用后置处理,如果后置处理返回的bean不为空,则直接返回

        // 返回的是一个寡妇对象, 属性什么的, spring不会去维护

        // spring不推荐开发人员使用这个接口 InstantiationAwareBeanPostProcessor

        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

        if (bean != null) {

            return bean;

        }

    }

    catch (Throwable ex) {

        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,

                "BeanPostProcessor before instantiation of bean failed", ex);

    }

    try {

        // 创建bean

        Object beanInstance = doCreateBean(beanName, mbdToUse, args);

        if (logger.isTraceEnabled()) {

            logger.trace("Finished creating instance of bean '" + beanName + "'");

        }

        return beanInstance;

    }

    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {

        // A previously detected exception with proper bean creation context already,

        // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.

        throw ex;

    }

    catch (Throwable ex) {

        throw new BeanCreationException(

                mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);

    }

}

深圳网站建设www.sz886.com

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

推荐阅读更多精彩内容