乐趣区

Spring-GetBean流程

 第一节讲解 Spring 启动的时候说到,Spring 内部先解析了所有的配置,加载所有的 Bean 定义后,再根据需要对 Bean 进行实例化和初始化。除开 Spring 自己主动新建的对象,第一次根据 Bean 定义加载对象的动作出现在 AbstractApplicationContext 的 invokeBeanFactoryPostProcessors 方法,该方法会在 Spring 容器中找出实现了 BeanFactoryPostProcessor 接口的 bean 列表并执行。根据之前介绍的内容,内部主要调用了 AbstractBeanFactory 的 getBean 方法,这节将对该方法进行讲解。

一、getBean

 在这之前,先介绍 BeanFactory 的层次结构,如下:

涉及到的接口和实现类为:

 AliasRegistry:别名管理接口,定义了别名管理的功能

 SimpleAliasRegistry:AliasRegistry 的默认实现,内部用一个

 ConcurrentHashMap:管理别名

 SingletonBeanRegistry:单例实例管理接口,定义了单例管理的功能

 DefaultSingletonBeanRegistry:单例管理实现类,内部用 Map 维护着被实例化后的所有单例、单例工厂等相关信息。Map 的键为 bean 的唯一标识,Spring 内部成为 raw name,一般等同于 Bean 定义中的 id 或者 name 或者别名等,具体规则可以从上节 BeanDefinition 的加载查看,值为相应的对象实例。这边需要指出的一点是,对于 bean 定义中具有别名意义的字段,如一定情况下的 name 以及 alias 字段,只存在于 SimpleAliasRegistry 维护的内部 Map 中,通过递归查询的方式可以从一个给定的别名查找到指定的 id。

 如下,DefaultSingletonBeanRegistry 维护的 Map 中存在 key 为 testBean,value 为 TestBean 的对象,SimpleAliasRegistry 维护的 Map 中存在 Key 为 testBeanAlias1,value 为 testBean 的记录。当通过 testBeanAlias1 查找 bean 时,会先通过 AliasRegistry 查找到 testBean,再从通过 BeanRegistry 查找到对应的 Bean 实例。

 FactoryBeanRegistrySupport:增加缓存 FactoryBean 实例功能,DefaultSingleBeanRegistry 在生成单例后便不再持有对应的 FactoryBean

 BeanFactory:定义了 Bean 容器的基本查询接口,同时设定了以 & 前缀来区别工厂 Bean,即如果 beanName 前面有 & 则返回对应 Bean 的工厂 Bean 对象而不是该 Bean 对象。

 HierarchicalBeanFactory:在 BeanFactory 接口上增加了父子层级关系,以实现双亲委托。

 ConfigurableBeanFactory:按照规矩,增加了修改功能的接口,同时增加了 Scope 特性,默认分为 single 单例和 prototype 多例。

 AbstractBeanFactory:BeanFacoty 的基本实现。

 AbstractBeanFactory 的 getBean 方法内部调用了 doGetBean,该方法提供了根据 beanName 获取实例的具体实现,代码如下(删除了相关的注释和空格):


protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
            throws BeansException {/*(1)*/
        final String beanName = transformedBeanName(name);
        Object bean;
        /*(2)*/
        Object sharedInstance = getSingleton(beanName);
        /*(3)*/
        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 + "'");
                }
            }
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
        /*(4)*/
        else {/*(5)*/
            if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);
            }
            /*(6)*/
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {String nameToLookup = originalBeanName(name);
                if (args != null) {return (T) parentBeanFactory.getBean(nameToLookup, args);
                }
                else {return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }
            /*(7)*/
            if (!typeCheckOnly) {markBeanAsCreated(beanName);
            }
            try {/*(8)*/
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
                /*(9)*/
                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);
                        }
                    }
                }
                /*(10)*/
                if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            try {return createBean(beanName, mbd, args);
                            }
                            catch (BeansException ex) {destroySingleton(beanName);
                                throw ex;
                            }
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }
                /*(11)*/
                else if (mbd.isPrototype()) {
                    Object prototypeInstance = null;
                    try {beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    }
                    finally {afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                }
                /*(12)*/
                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<Object>() {
                            @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) {/*(13)*/
                cleanupAfterBeanCreationFailure(beanName);
                throw ex;
            }
        }
        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());
            }
        }
        return (T) bean;
    }

先说下入参:

  1. name:要查找的 bean 名,可以为 raw name,也可以为 alias name 或者 factoryBean name,Spring 内部会自行进行转换。
  2. requiredType:要返回的对象类型
  3. args:对象实例化时需要用到的构造参数
  4. typeCheckOnly:该对象只是用来进行类型检查,而不会真正的进行使用,可以避免实例化和初始化对象

具体过程为:

1. 获取 raw name

 计算所给 name 对应的内部 beanName,具体为循环去除 name 前面的 &,再根据之前的介绍的,如果传入的是别名,会查找到对应的 raw name

2. 尝试获取 bean 实例

 使用上面获得的 beanName,调用内部的 getSingleton 方法,获取对应的对象实例,赋值给 sharedInstance。getSingleton 方法来自于 DefaultSingletonBeanRegistry,即这步尝试直接从内部维护的单例 Map 中获取实例。这步可以检测到手工注入的 singleton,如第一节提到的 ApplicationContext 对象,就是 Spring 自己手动注册的。

3.bean 实例已经存在

 若 sharedInstance 不为空,且 args 参数为空,说明该对象已经存在,不需要再进行实例化和初始化。由于在 (1) 的时候对所传的 name 去除了 &,需要判断返回的对象是否符合要求。这时候,会使用 getObjectForBeanInstance 方法,对 sharedInstance 和 name 进行判断,返回对应的实例,该方法主要内容如下:

1) 若 name 以 & 开头,但 sharedInstance 没有实现 FactoryBean 接口,则抛出异常

2) 若 sharedInstance 没有实现 FactoryBean 接口,或者 name 以 & 开头,则直接将 sharedInstance 对象返回。即 sharedInstace 本身是从 name 对应的 FactoryBean 获取的对象。

3) 若前面 2 个条件都不符合,则 sharedInstance 本身实现了 FactoryBean 接口,name 也是以 & 开头,这时候会尝试从 FactoryBeanRegistrySupport 中根据 beanName(raw name)获取已经实例化的对象。若对象为空,即首次获取,则将 sharedInstace 转为 FactoryBean, 并调用该工厂方法获取对象。这里涉及到 FactoryBeanRegistrySupport 的 getObjectFromFactoryBean 方法,该方法在使用 FactoryBean 获得对象后,会调用上下文中已有的 BeanPostProcessor 对象列表,逐个执行 postProcessAfterInitialization 方法,当遇到处理后的结果为空,则直接返回,否则继续遍历执行,如下,出现在 AbstractAutowireCapableBeanFactory 中:

4.Bean 实例不存在

 如果没有找到 beanName 对应的实例,即不存在对应的单例实例,则转入实例化该对象的流程,注意单例或者多例都需要实例化。

5. 如果该 beanName 有对应的在初始化中的多例对象,则抛出异常。

 AbstractBeanFactory 内部维护了一个 ThreadLocal 对象,用于维护当前线程正在初始化的多例对象。

6. 启用双亲委托机制

 如果存在父容器,且父容器存在该 beanName 的定义,则委托给父容器完成。

7. 如果本次调用不单是为了类型检查,则标记该 beanName 在创建中

 AbstractBeanFactory 内部维护了一个 Set<String> 集合 alreadyCreated,用于存储已经创建好或者正在创建的 bean

8. 获取该 beanName 对应的 BeanDefinition, 包装为 RootBeanDefinition 返回。

 AbstractBeanFactory 内部维护了一个 Map<String, RootBeanDefinition> 集合 mergedBeanDefinitions,用于维护当前已经加载的各个 bean 定义 bd。在加载该 bean 定义时,如果存在父定义 pdb,则会将 pdb 包装为一个 RootBeanDefinition,然后将当前的 bd 覆盖掉父定义的内容,包括 scope、lazyInit、dependsOn 等属性,达到继承的效果。获得 RootBeanDefinition 后,如果最后的定义中 scope 为空,则会默认赋值为 single。此外还有一个 containingBd 的概念,这个是相对于 bd 来说的,指的是包含 bd 的外部 bean 定义,主要用于 inner bean 的情况。如果包含 containingBd 不为空,且不是单例,但是 bd 为单例,则 bd 的 scope 需要设置为 containingBd 的值,直白点说就是包含被非单例 bean 包含的 bean 本身不能为单例(这段有点绕,还没找到实际的例子,直接按照代码里的直译过来)。

9. 处理依赖的 bean

 获取该 bean 依赖的 bean 列表 dependsOn 值,对每个依赖的 bean 进行逐一操作,先检查该 bean 是否存在循环依赖,若不存在循环依赖,则将依赖关系缓存起来,最后先实例化依赖的 bean。其中检查循环依赖很重要,如果没有该步,最后实例化依赖的 bean 时会导致死循环。为此 AbstractBeanFacotry 内部维护了两个 Map<String, Set<String>> 属性 dependentBeanMap 和 dependenciesForBeanMap,分别用于缓存 bean 的依赖关系。前者表示 bean 从属关系的缓存,缓存依赖于 key 所表示的 bean 的所有 bean name,举例来讲,如果 beanB 的一个属性是 beanA, 则 beanA 为 key 是被依赖方,beanB 则为 value 是依赖方 (从属方) 的一员;后者标识 bean 依赖关系的缓存,缓存 key 所表示的 bean 依赖的所有 bean name, 举例来讲,如果 beanB 的一个属性是 beanA, 则 beanB 是 key 从属方,beanA 则是 value 被依赖方的一员。如下为 Spring 检查循环依赖的过程:

 其中 beanName 为当前 bean,dependentBeanName 为当前 bean 所依赖的 bean。大致过程为找出所有依赖 beanName 的 bean 列表 transitiveDependency,递归判断 transitiveDependency 是否也依赖 dependentBeanNam,即如果 beanName 依赖于 dependentBeanName,而且 transitiveDependency 依赖于 beanName, 如果 transitiveDependency 依赖于 dependentBeanName,即出现了环,则存在循环依赖。

10. 如果该 bean 为单例,则转入初始化单例流程

 调用父类 DefaultSingletonBeanRegistry 的 getSingleton 模板方法,该模板方法会保证该单例只有被创建一次,创建完成后将对象缓存在内部。真正实例化和初始化的过程在 createBean 方法中,其中如果该 bean 实例化失败,则会调用 destroySingleton 方法进行回收,这两个方法在后面会进行重点讲解。同第二步类似,获取该对象后,会再调用 getObjectForBeanInstance 检查 FactoryBean。

11. 如果该 bean 为多例,则转入初始化多例流程

 第(5)步讲过,内部有一个 ThreadLocal,保证多例在当前线程创建时是唯一的,重点方法也是 createBean。需要注意的是,如果是多例,创建失败是不会进行回收的。

12. 如果该 bean 为其他 scope,则转入对应的初始化流程

 具体过程同 (10) 一致,只是调用的模板委托给了具体的 Scope 对象。

13. 初始化失败,则清理相关内容

 将该 beanName 从 alreadyCreated 移除,标识该 beanName 还未创建。

二、createBean

 createBean 方法主要用于完成 bean 的实例化和初始化过程,该方法在 AbstractFactory 中为抽象方法,具体实现是在 AbstractAutowireCapableBeanFactory 类中。如下为核心操作:

1.resolveBeforeInstantiation

 创建对象前的代理口子,能够拦截创建过程,使用自定义的代理对象来替换 Spring 内部正常创建的对象,即上面判断的,如果该方法返回对象不为空,则直接使用返回的对象返回。实现上,会逐一遍历所有的 BeanPostProcessor,找出 InstantiationAwareBeanPostProcessor 对象,并执行 postProcessBeforeInstantiation 方法,若返回结果不为空,则直接使用该方法返回,如下:

 该方法主要用在 AOP 实现上,上节提到的 CommonAnnotationBeanPostProcessor 和 PersistenceAnnotationBeanPostProcessor 类虽然实现了该接口,但是 postProcessBeforeInstantiation 方法为空实现。

 若该方法返回对象不为空,则会逐一执行 BeanPostProcessor 列表的 postProcessAfterInitialization 方法,以完成回调。

2.doCreateBean

 该方法的主要过程如下,省略了提前暴露 bean 实例的部分内容。

 由上图可知,该过程完成了 bean 的实例化和初始化以及调用各回调接口的过程。具体为:

1) 根据 BeanDefinition 实例化 bean

 主要尝试从各种方法进行实例化,包括:

a. 使用工厂方法进行实例化

b. 使用 bean 定义的构造方法或者可用的构造方法进行实例化

c. 使用默认的构造方法进行实例化

2) 回调 MergedBeanDefinitionPostProcessor 的 postProcessMergedBeanDefinition 方法

 如下,遍历各个 MergedBeanDefinitionPostProcessor 实例,回调 postProcessMergedBeanDefinition 方法

3. 初始化对象,填充各属性

 执行初始化,实现属性的依赖注入,在自动进行依赖注入前,会先调用一个回调接口,以判断是否需要自动依赖注入,如下:

 通过回调 InstantiationAwareBeanPostProcessor 的 postProcessAfterInstantiation 方法来判断。

 若需要进行依赖注入,则会根据依赖策略:根据 autowireByName 或者 autowireByType,为属性字段找到符合定义的 bean 实例(会通过 getBean 方法调用)。在真正将值赋值给属性前,还会再次执行回调接口,如下,回调 InstantiationAwareBeanPostProcessor 的 postProcessPropertyValues 方法,这里也可以进行拦截。

 若前面都没被拦截到,则会真正将 bean 值复制给对应的属性,最终会通过反射设置 field 的 accessable,然后将 bean 实例设置进去。

4. 执行各回调接口

1) 执行 Aware 接口,包括 BeanNameAware、BeanClassLoaderAware 和 BeanFactoryAware

2) 执行 BeanPostProcessor 的 postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor 类实现了该方法,用以回调 @PostConstruct 注解的方法,CommonAnnotationBeanPostProcessor 继承自该类,设置了 initAnnotationType 为 PostConstruct.class)方法

3) 如果该 Bean 实现了 InitializingBean 接口,则调用 afterPropertiesSet 方法

4) 如果设置了 init-method, 则执行 init-method 指定的方法

5) 执行 BeanPostProcessor 的 postProcessAfterInitialization 方法

5. 判断是否有销毁接口,并添加到列表中

 如下,为处理过程,会先判断当前 bean 定义不是多例,且需要进行销毁回调,才会进行处理。如果是单例,则直接将其添加到响应列表列表中进行缓存,存储在内部维护的 disposableBeans 列表中;如果是其他 socpe,则将其委托给对应的 Scope 对象实现。

 这里有几个条件:

1) 必须为非 prototy

2) 该 bean 存在销毁方法,满足一下条件之一即是

a. 该 bean 实现了 DisposableBean 接口

b. 该 bean 实现了 AutoCloseable 接口

c. 该 bean 实现了 Closeable 接口

d. 该 bean 定义的 destory-method 不为空

e. 该 bean 符合 DestructionAwareBeanPostProcessor.requiresDestruction 方法的过滤条件

 只要符合以上条件,就会新建一个 DisposableBeanAdapter 对象进行存储,并在销毁时进行相应的接口回调。

三、回调接口顺序

 结合之前几节内容,可以得到如下的回调顺序:

 以上为大致的过程,不含其它的回调接口,若有其它回调接口可以按照顺序依次加入。

个人公众号:啊驼

退出移动版