第一节讲解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中:

  1. Bean实例不存在

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

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

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

  3. 启用双亲委托机制

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

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

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

  5. 获取该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本身不能为单例(这段有点绕,还没找到实际的例子,直接按照代码里的直译过来)。

  6. 处理依赖的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,即出现了环,则存在循环依赖。

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

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

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

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

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

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

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

    将该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方法

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

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

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

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

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

  2. 执行各回调接口

    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方法

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

    如下,为处理过程,会先判断当前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对象进行存储,并在销毁时进行相应的接口回调。

三、回调接口顺序

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

阶段 动作 回调接口 备注
启动 Context执行invokeBeanFactoryPostProcessors BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry 继承自BeanFactoryPostProcessor
BeanFactoryPostProcessor.postProcessBeanFactory 按照PriorityOrdered、Ordered、一般执行;不重复执行
BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry
实例化 从FactoryBean中获取实例 BeanPostProcessor.postProcessAfterInitialization 从FactoryBean获取Bean的话不会执行下面的初始化回调
resolveBeforeInstantiation(代理口子) InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 继承自BeanPostProcessor
BeanPostProcessor.postProcessAfterInitialization 这里返回对象非空不会执行下面的初始化回调
doCreateBean MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
InstantiationAwareBeanPostProcessor.postProcessPropertyValues
BeanNameAware.setBeanName 初始化后执行invokeAwareMethods
BeanClassLoaderAware.setBeanClassLoader
BeanFactoryAware.setBeanFactory
BeanPostProcessor.postProcessBeforeInitialization
InitializingBean.afterPropertiesSet
init-method
BeanPostProcessor.postProcessAfterInitialization
DestructionAwareBeanPostProcessor.requiresDestruction 销毁方法检查
初始化后 preInstantiateSingletons SmartInitializingSingleton.afterSingletonsInstantiated

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

个人公众号:啊驼

Spring GetBean流程的更多相关文章

  1. Spring.getBean()流程和循环依赖的解决

    getBean流程介绍(以单例的Bean流程为准) getBean(beanName) 从BeanFactory中获取Bean的实例对象,真正获取的逻辑由doGetBean实现. doGetBean( ...

  2. Spring(六)Spring执行流程

    Spring MVC工作流程图 Spring工作流程描述 1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获: 2. DispatcherS ...

  3. Java框架之SpringMVC 05-拦截器-异常映射-Spring工作流程

    SpringMVC 拦截器 Spring MVC也可以使用拦截器对请求进行拦截处理,可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口中的三个方法,也可以 ...

  4. 概括的描述一下Spring注册流程

    Spring经过大神们的构思.编码,日积月累而来,所以,对其代码的理解也不是一朝一夕就能快速完成的.源码学习是枯燥的,需要坚持!坚持!坚持!当然也需要技巧,第一遍学习的时候,不用关注全部细节,不重要的 ...

  5. Spring 初始化流程

    开始 在SpringIOC中,前面讲述了如何配置BeanDefinition和如何注册BeanDefinition,但是这些知识容器初始化的一部分,在AbstractApplicationContex ...

  6. spring 启动流程

    AbstractApplicationContext 分析 启动流程 // Prepare this context for refreshing.prepareRefresh(); 1. // In ...

  7. spring getbean 方法分析

    spring 缺省: 1.spring用DefaultListableBeanFactory.preInstantiateSingletons()建立bean实例 2.缺省采用单例模式 在最近的项目中 ...

  8. Spring MVC流程

    这是spring mvc框架结构图,图片是很早在网上撸过来的,具体在哪忘了…… 早期学习Springmvc 并没有具体了解过,只知道这样用很爽,最近了解下基本结构流程及组件所在…… 执行流程 Spri ...

  9. shiro集成spring&工作流程&DelegatingFilterProxy

    1.集成Spring 参考文献: 新建web工程: ehcache-core来自Hibernate wen.xml <?xml version="1.0" encoding= ...

随机推荐

  1. mysql迁移mpp数据库Greenplum

    1. 场景描述 因兄弟项目中mysql有点扛不住了,要做sql优化,但是业务有点小复杂,优化起来有点麻烦(sql嵌套有点多),便想着用Mpp数据库Greenplum测试下,看性能和复杂度怎么样,趟趟水 ...

  2. 多线程编程学习六(Java 中的阻塞队列).

    介绍 阻塞队列(BlockingQueue)是指当队列满时,队列会阻塞插入元素的线程,直到队列不满:当队列空时,队列会阻塞获得元素的线程,直到队列变非空.阻塞队列就是生产者用来存放元素.消费者用来获取 ...

  3. 01 Python 基础数据类型

    基础数据类型,有7种类型,存在即合理. 1.int 整数 主要是做运算的 .比如加减乘除,幂,取余  + - * / ** %...2.bool 布尔值 判断真假以及作为条件变量3.str 字符串 存 ...

  4. python控制窗口显示隐藏

    import win32con # 定义 import win32gui # 界面 import time # 时间 QQ= win32gui.FindWindow("TXGuiFounda ...

  5. 牛客2018多校第六场 J Heritage of skywalkert - nth_element

    传送门 题意:提供一个随机生成函数,让你生成n个数,然后问你其中能找到的两个数的最小公倍数 最大 是多少. 思路:可以用nth_element()函数在O(n)下求出前 15 个大的数(当然,100个 ...

  6. CodeForces 1105E Helping Hiasat 最大独立集

    Helping Hiasat 题解: 如果我们把连续的2出现的人都相互连边的话, 题目就是问最大独立集的答案是多少. 求最大独立集可以将图变成反图, 然后求最大团. 代码: #include<b ...

  7. 【Offer】[51] 【数组中的逆序对】

    题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.例如,在数组 ...

  8. 阿里云 windows frp 远程桌面

    环境: 阿里云服务器 server 2008 ,想要被远程访问的终端(本机)是win7 x64 目的:实现在别的地方(家里,出差在外) 用 远程桌面 访问 位于公司内部的电脑 frp 介绍:https ...

  9. [翻译] .NET Core 3.0 RC 1 发布

    原文: Announcing .NET Core 3.0 Release Candidate 1 今天,我们宣布推出 .NET Core 3.0 Release Candidate 1.就像 Prev ...

  10. .Net基础篇_学习笔记_第七天_计算质数(找出0-100以内说有质数)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...