Spring源码(五)-获取Bean-getBean

在上一篇我们已经阅读过一部分 getBean 的源码了,如果从单例池中获取到了实例,就对这个实例进行判断是否是FactoryBean,如果是FactoryBean,那么真正需要拿到的是 getObject方法所返回的对象。这节继续往下看,如果没有从单例池中获取到实例,Spring 会干嘛?

单例池没有获取到Bean

//上面代码省略---
//单例池没有获取到Bean
        else {
            // 指定的原型bean是否正在创建中  如果是则抛出异常
            // Spring不支持原型bean的循环依赖
            // 当前正在创建的原型Bean都会被放在 prototypesCurrentlyInCreation 这个ThreadLocal中 
            //1、
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
            //2、
            //获得父级BeanFactory
            BeanFactory parentBeanFactory = getParentBeanFactory();
            //当前容器的父级容器存在且当前容器中不存在指定名称的BeanDefinition,
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                //将用户指定的bean名称解析为规范名称,并拼接上 & 符号
                String nameToLookup = originalBeanName(name);
                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);
                }
            }
          //`3、
            // 将指定的bean标记为已创建(或将要创建)。
            // typeCheckOnly 上层传入为 false
            // 可以去看 Spring源码(二)-XML文件的读取-BeanDefinitionReader 这篇文章 其中有个方法 hasBeanCreationStarted()
            // markBeanAsCreated方法就是往 alreadyCreated 这个 Set 中添加数据
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }
  
            try {
                //4、
                // 得到合并后的RootBeanDefinition
                //如果指定BeanName是子Bean的话同时会合并父类的相关属性
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                //检查给定的合并bean定义
                checkMergedBeanDefinition(mbd, beanName, args);
                //确保当前bean依赖的bean已经初始化。先加载DependsOn所指定的bean
                //xml写法
                //<bean class="com.gongj.bean.Person" id="person" depends-on="user"></bean>
                //<bean class="com.gongj.bean.User" id="user" depends-on="person"></bean>
                //注解写法
                //@DependsOn("user")
                //获取当前Bean所有依赖Bean的名称  比如当前beanName为A, A依赖了B
                String[] dependsOn = mbd.getDependsOn(); // dependsOn也就是为 B
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        // 判断beanName(A)是不是也被dep(B)依赖了,如果是,就是相互依赖,抛出异常
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        // 存在在两个map中
                        // 1. dependentBeanMap,key为dep(B), value是一个LinkedHashSet,表示dep(B)被哪些bean(A...)依赖了
                        // 2. dependenciesForBeanMap,key为beanName(A),value是一个LinkedHashSet,表示beanName(A)依赖了哪些dep(B) bean
                        registerDependentBean(dep, beanName);
                        try {
                            // 先去生成所依赖的bean
                            getBean(dep);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }
                //5、
                // 根据Scope去创建bean
                //创建单例模式Bean的实例对象
                if (mbd.isSingleton()) {
                    //使用一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                                return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            //显式地从容器单例模式Bean缓存中清除实例对象
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    // sharedInstance可能是一个FactoryBean,如果是FactoryBean
                    // 那么真正需要拿到的是getObject方法所返回的对象
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
            //6、
                //创建原型模式Bean实例对象
                else if (mbd.isPrototype()) {
                    Object prototypeInstance = null;
                    try {
                        // 将当前创建的Bean标记为创建中 操作的也就是 prototypesCurrentlyInCreation 这个属性
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {
                        // 创建完成,从prototypesCurrentlyInCreation移除beanName
                        afterPrototypeCreation(beanName);
                    }
                    // prototypeInstance可能是一个FactoryBean,如果是FactoryBean,
                    // 那么真正需要拿到的是getObject方法所返回的对象
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }
                //如果要创建的Bean的生命周期范围不是singleton,也不是prototype
                //则从 this.scopes.get(scopeName) 获取生命周期; 实例化Bean
                //如:request、session等生命周期
              //7、
                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, () -> {
                            // 将当前创建的Bean标记为创建中 操作的也就是 prototypesCurrentlyInCreation 这个属性
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                // 创建完成,从prototypesCurrentlyInCreation移除beanName
                                afterPrototypeCreation(beanName);
                            }
                        });
                        // scopedInstance可能是一个FactoryBean,如果是FactoryBean,
                        // 那么真正需要拿到的是getObject方法所返回的对象
                        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;
            }
        }
  • 1、:Spring 首先检查 beanName 是否在prototypesCurrentlyInCreation 中,prototypesCurrentlyInCreation是一个 ThreadLocal,存储了当前正在创建的原型beanName 集合,Spring 不支持原型 bean 的循环依赖,所以会抛出一个BeanCurrentlyInCreationException异常。
  • 2、:获取父级容器,如果当前容器的父级容器存在且当前容器中不存在指定名称的 BeanDefinition,就尝试去父容器中获取bean实例。
  • 3、:是否获取实例以进行类型检查,上传传入 false,然后进行取反,进入 markBeanAsCreated方法,将 beanName 加入alreadyCreated的 Set 集合中,存储已经创建好的或者正在创建中的 beanName,并调用 clearMergedBeanDefinition 方法,删除指定bean 的合并 bean 定义,并将 stale 设置为 true。stale 为 true 时才会进行 bean 合并。
  • 4、:将GernericBeanDefinition转换为RootBeanDefinition,如果指定 beanName 是子Bean 的话同时会合并父类的相关属性。如果当前 bean 有依赖 bean,则递归实例化依赖的bean,如果相互依赖,则抛出BeanCreationException异常。
  • 5、:如果 Bean 的作用域为 singleton,则创建单例Bean的实例对象。在这里 Spring 调用了一个重载的getSingleton(String beanName, ObjectFactory<?> singletonFactory)方法实现了 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);

            // 如果不存在实例,则创建单例bean实例
            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中,
                // singletonsCurrentlyInCreation是一个Set
                //表示这些bean正常创建中,在没创建完时不能重复创建
                beforeSingletonCreation(beanName);
                boolean newSingleton = false;
                boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
                if (recordSuppressedExceptions) {
                    this.suppressedExceptions = new LinkedHashSet<>();
                }
                try {
                    // singletonFactory是外面传进来的lambda表达式,执行lambda表达式
                    //就是调用 createBean()
                    // 创建单例bean
                    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;
                    }
                    // 将刚刚正在创建的beanName从singletonsCurrentlyInCreation中移除
                    afterSingletonCreation(beanName);
                }

                // 将创建好的单例bean添加到单例池singletonObjects中
                //和单例注册表registeredSingletons中
                //并清除二级、三级缓存  
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }
  • 6:如果 Bean 的作用域为 prototype,则创建原型模式Bean实例对象。直接调用 createBean 方法,原型模式下,每次 getBean 都会创建新的对象实例。
  • 7:如果 Bean 的作用域不是 singleton 和 prototype,则从 this.scopes.get(scopeName) 获取作用域, 实例化Bean。

类型检查

看看就好了。

//检查所需类型是否与实际bean实例的类型匹配
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的名称
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
            new NamedThreadLocal<>("Prototype beans currently in creation");
            
//bean定义对象,key为beanName
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

//合并的RootBeanDefinition,key为beanName
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

//存储已经创建好的或者正在创建中的beanName
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

//单例池
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

//单例工厂的缓存, Bean名称到ObjectFactory,一旦最终对象被创建(通过objectFactory.getObject()),此引用信息将删除  二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);  

//用于存储在创建Bean早期对创建的原始bean的一个引用,注意这里是原始bean,即使用工厂方法或构造方法创建出来的对象,
//一旦对象最终创建好,此引用信息将删除 三级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

//当前在创建检查中排除的bean名称
private final Set<String> inCreationCheckExclusions =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));
            
//当前正在创建的bean的名称,表示这些bean正常创建中,在没创建完时不能重复创建
private final Set<String> singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));

// 已注册的单例beanName
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

下篇开始 createBean 的源码阅读,想想都有点激动。

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

推荐阅读更多精彩内容