美文网首页
吃透spring中的getBean

吃透spring中的getBean

作者: rock_fish | 来源:发表于2019-12-11 10:24 被阅读0次

    传送:

    Spring大观园,我有过的困惑或许你也有!


    前置知识点

    假定你已或多或少知晓如下知识点(如果以前不知道,看完你就算知道了...)

    • spring中有BeanFactory(容器)。
    • Bean容器可以有多个,彼此之间从逻辑上组成链表(父子关系),且单向可见(子可见父)。
    • spring中通过BeanFactoryPostProcessor解析配置类,扫描组件,注册BeanDefinition,类似于JVM中扫描加载类
    • spring 根据BeanDefinition来创建Bean,类似于JVM中根据Class创建Object.
    • BeanFactory中有几个缓存,存储BeanDefinition,单例bean等。
    • 循环依赖处理方法论
    对象创建 VS Bean创建

    BeanDefinition vs Class
    spring有自己的一套管理对象的机制,比如是否单例,什么时候实例化,实例化后的自定义初始化等等;这些特性都是在JVM的Class之外的东西,要把这些个性化的东西存封装起来于是变有了BeanDefinition,Class信息只是其一个属性。
    Bean vs Object

    • Bean本身就是Object,new出来一个Object只是创建Bean的第一步;
    • 实例化Object 到Bean创建完成之间,spring还规范了好几个步骤,这些步骤构成了Bean的生命周期(一部分)。
    getBean的知识点

    我们从不同的角度来拆解Bean创建的知识点,后边再从源码中将这些知识点串联起来,更便于理解源码。

    • spring认为Bean的创建是自己的事情,因此spring对外提供的方法是getBean;createBean在getBean的方法内部。
    • 对于单例Bean的情况下getBean内部有两个逻辑:
      1.从缓存中拿,如果BeanFactory中有缓存,就直接返回。
      2.缓存没有就创建,创建后放入BeanFactory缓存中,于是有了逻辑1;其创建过程中还会用到几个缓存,后边会提及。
      另外对于prototype来说,每次都创建。
    • 容器之间构成父子链路,getBean的时候优先调用父Factory中getBean,即先从祖宗Factory的getBean中去获取(创建)
    • bean的创建需要其BeanDefinition,调用getBeanDefinition方法,根据bean名称从beanDefinitionMap的拿到BeanDefinition.
    • FactoryBean很绕口的描述是:创建Bean的Bean;获取其自身需要在bean的名称前加上&符号。
    • spring把Bean的创建分了几个步骤,
      1. 记录Bean开始创建状态(循环依赖的时候,避免重复创建)。
      2. 实例化对象
      3. 装配属性;依赖注入,依赖bean处理
      4. BeanPostProcessor,初始化的扩展点,这里是spring给使用者的扩展点,用户可以参与bean的创建过程,甚至替换对象
      5. 返回对象(单例的缓存到单例池)
    • 循环依赖的处理只支持单例模式

    理解记忆这些知识点,下边源码中的流程就基本都能理解了。

    源码中的流程
    1. 获取实际的beanName,处理FactoryBean(带&号前缀的beanName)和别名换成原名。
    2. 从缓存中获取此beanName的bean
    3. 如果beanName的实例存在于缓存中
    4. prototype类型bean的循环依赖检测。
    5. 检查bean是否存在于父类工厂中,若存在,则走父类工厂的getBean流程。向上委托,保证容器中只会存在一个同名的bean。
    6. 标记Bean为已创建或即将创建。
    7. 获取BeanDefinition ;如果有父类,这里会递归合并父类的方法以及属性。并会用自己重写的方法覆盖其父类的方法。合并完成并检查这个bean的是否是抽象类。
    8. 依赖Bean处理 ;如果该bean上有注解@DependsOn,或者配置文件<bean depends-on="..."/>上配置有该属性,则需保证该bean的所有依赖需要先在容器内注册。
    9. 不同作用域的Bean实例化;分单例和原型以及其他scope类型来创建bean。
    10. 类型转换 ;检查beanName类型是否符合需要的类型,若不符合,尝试进行转换。
    11. 返回创建好的bean。

    源码解读

    AbstractBeanFactory#doGetBean

    1. 获取实际的beanName
    inal String beanName = transformedBeanName(name);
    
    1. 如果有&,去掉&;&是从Spring中取FactoryBean的时候,在bean名称前+&;更多FactoryBean的信息看FactoryBean是bean还是Factory?

    2. 别名换成原名;从Map<String, String> aliasMap 中获取原名

    2. 从缓存中获取此beanName的bean
    // Eagerly check singleton cache for manually registered singletons.
    Object sharedInstance = getSingleton(beanName);
    

    强力建议先看 吃透Spring的循环依赖 把这个函数的作用分析的很透彻。

    3.如果beanName的实例存在于缓存中
    if (sharedInstance != null && args == null) {
        // 3.如果beanName的实例存在于缓存中
        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.1 返回beanName对应的实例对象(主要用于FactoryBean的特殊处理,普通Bean会直接返回sharedInstance本身)
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    
    4. prototype类型bean的循环依赖检测。

    强力建议先看 吃透Spring的循环依赖 把这个函数的作用就理解了。

    spring规范了bean创建的流程可以从模板方法模式的角度来看率, BeanFactory接口中没有
    AbstractBeanFactory#getBean(java.lang.String)

        @Override
        public Object getBean(String name) throws BeansException {
            return doGetBean(name, null, null, false);
        }
    
    5. 从parentBeanFactory中获取Bean
    // Check if bean definition exists in this factory.
    BeanFactory parentBeanFactory = getParentBeanFactory(); // 获取父factory
    
    // containsBeanDefinition(beanName) -> 判断该beanName的BeanDefinition是否在该factory中
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
        // 有父factory存在并且当前factory不包含该beanName,则尝试从父factory中加载bean
        // Not found -> check parent.
        String nameToLookup = originalBeanName(name); // 若有多个'&'值保留一个或者别名转换为原名
        if (parentBeanFactory instanceof AbstractBeanFactory) {
            // 递归调用父类 doGetBean 方法
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
        }
        else if (args != null) {
            // // 用明确的 args 从 parentBeanFactory 中,获取 Bean 对象
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
        }
        else if (requiredType != null) {
            // 用明确的 requiredType 从 parentBeanFactory 中,获取 Bean 对象
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
        }
        else {
            // 直接使用 nameToLookup 从 parentBeanFactory 获取 Bean 对象
            return (T) parentBeanFactory.getBean(nameToLookup);
        }
    }
    

    父容器的场景其实在Springmvc的父容器是Spring容器,Servlet规范和Servlet容器 笔记的末尾中有说清楚。
    从这个getBean的委托父容器的流程可以解释为什么子容器可以引用父容器中的Bean,而父容器不可以引用子容器中的Bean

    6. 标记Bean为已创建或即将创建

    Set<String> alreadyCreated存储bean名称;在set中表示bean已开始创建

    // 如果不是仅做类型检查,而是创建bean,则需要标记该beanName为已经开启创建
    if (!typeCheckOnly) {
        markBeanAsCreated(beanName);
    }
    //具体实现
    protected void markBeanAsCreated(String beanName) {
        if (!this.alreadyCreated.contains(beanName)) {
            synchronized (this.mergedBeanDefinitions) {
                if (!this.alreadyCreated.contains(beanName)) {
                    // Let the bean definition get re-merged now that we're actually creating
                    // the bean... just in case some of its metadata changed in the meantime.
                    clearMergedBeanDefinition(beanName);
                    //添加到一个set集合中
                    this.alreadyCreated.add(beanName);
                }
            }
        }
    } 
    
    7 获取BeanDefinition
    //根据beanName重新获取MergedBeanDefinition(步骤6将MergedBeanDefinition删除了,这边获取一个新的)
    //如果有父类,这里会递归合并父类的方法以及属性。并会用自己重写的方法覆盖其父类的方法。合并完成并
    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    // 检查给定的合并的 BeanDefinition 是否是抽象类
    checkMergedBeanDefinition(mbd, beanName, args);
    

    下边描述MergedBeanDefinition的内容来自:https://blog.csdn.net/v123411739/article/details/87907784

    MergedBeanDefinition:这个词其实不是一个官方词,但是很接近,该词主要是用来表示 “合并的 bean 定义”,因为每次都写 “合并的 bean 定义” 有点太绕口,因此我在之后的注释或解析中或统一使用 MergedBeanDefinition 来表示 “合并的 bean 定义”。
    之所以称之为 “合并的”,是因为存在 “子定义” 和 “父定义” 的情况。对于一个 bean 定义来说,可能存在以下几种情况:

    1. 该 BeanDefinition 存在 “父定义”:首先使用 “父定义” 的参数构建一个 RootBeanDefinition,然后再使用该 BeanDefinition 的参数来进行覆盖。
    2. 该 BeanDefinition 不存在 “父定义”,并且该 BeanDefinition 的类型是 RootBeanDefinition:直接返回该 RootBeanDefinition 的一个克隆。
    3. 该 BeanDefinition 不存在 “父定义”,但是该 BeanDefinition 的类型不是 RootBeanDefinition:使用该 BeanDefinition 的参数构建一个 RootBeanDefinition。

    之所以区分出2和3,是因为通常 BeanDefinition 在之前加载到 BeanFactory 中的时候,通常是被封装成 GenericBeanDefinition 或 ScannedGenericBeanDefinition,但是从这边之后 bean 的后续流程处理都是针对 RootBeanDefinition,因此在这边会统一将 BeanDefinition 转换成 RootBeanDefinition。

    在我们日常使用的过程中,通常会是上面的第3种情况。如果我们使用 XML 配置来注册 bean,则该 bean 定义会被封装成:GenericBeanDefinition;如果我们使用注解的方式来注册 bean,也就是<context:component-scan /> + @Compoment,则该 bean 定义会被封装成 ScannedGenericBeanDefinition。

    理论了解后,可以从源码看MergedBeanDefinition

    8 依赖Bean处理

    如果该bean上有注解@DependsOn,或者配置文件<bean depends-on="..."/>上配置有该属性,则需保证该bean的所有依赖需要先在容器内注册

    // 8.拿到当前bean依赖的bean名称集合,在实例化自己之前,需要先实例化自己依赖的bean
    String[] dependsOn = mbd.getDependsOn();
    if (dependsOn != null) {
        // 8.1 遍历当前bean依赖的bean名称集合
        for (String dep : dependsOn) {
            // 8.2 检查dep是否依赖于beanName,即检查是否存在循环依赖
            if (isDependent(beanName, dep)) {
                // 8.3 如果是循环依赖则抛异常
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
            }
            // 8.4 将dep和beanName的依赖关系注册到缓存中
            registerDependentBean(dep, beanName);
            // 8.5 获取dep对应的bean实例,如果dep还没有创建bean实例,则创建dep的bean实例
            getBean(dep);
        }
    }
    
    
    9 不同作用域的Bean实例化
    // 9.针对不同的scope进行bean的创建
    if (mbd.isSingleton()) {
        // 9.1 scope为singleton的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
        sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
            @Override
            public Object getObject() throws BeansException {    //
                try {
                    // 9.1.1 创建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.
                    destroySingleton(beanName);
                    throw ex;
                }
            }
        });
        // 9.1.2 返回beanName对应的实例对象
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    } else if (mbd.isPrototype()) {
        // 9.2 scope为prototype的bean创建
        // It's a prototype -> create a new instance.
        Object prototypeInstance = null;
        try {
            // 9.2.1 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
            beforePrototypeCreation(beanName);
            // 9.2.2 创建Bean实例
            prototypeInstance = createBean(beanName, mbd, args);
        } finally {
            // 9.2.3 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
            afterPrototypeCreation(beanName);
        }
        // 9.2.4 返回beanName对应的实例对象
        bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
    } else {
        // 9.3 其他scope的bean创建,可能是request之类的
        // 9.3.1 根据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 {
            // 9.3.2 其他scope的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
            Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    // 9.3.3 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
                    beforePrototypeCreation(beanName);
                    try {
                        // 9.3.4 创建bean实例
                        return createBean(beanName, mbd, args);
                    } finally {
                        // 9.3.5 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
                        afterPrototypeCreation(beanName);
                    }
                }
            });
            // 9.3.6 返回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);
        }
    
    
    10 类型转换
    // 10.检查所需类型是否与实际的bean对象的类型匹配
    if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
        try {
            // 10.1 类型不对,则尝试转换bean类型
            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());
        }
    }
    
    11 返回bean
    // 11.返回创建出来的bean实例对象
    return (T) bean;
    

    感谢你们:

    GetBean源码全面解读
    Spring IoC:getBean 详解
    Spring的bean定义 4 : 合并了的bean定义--MergedBeanDefinition

    相关文章

      网友评论

          本文标题:吃透spring中的getBean

          本文链接:https://www.haomeiwen.com/subject/xsvggctx.html