springIoC源码解析过程,及解决循环依赖详解

xml解析:

  • XmlBeanFactory继承自DefaultListableBeanFactory,XmlBeanFactory使用XmlBeanDefinitionReader的loadBeanDefinitions方法将xml的Resource资源进行解析和读取。
  • XmlBeanDefinitionReader将xml资源委托给DefaultDocumentLoader类的loadDocument方法将xml的Resource转换为Document资源返回给XmlBeanDefinitionReader,XmlBeanDefinitionReader调用registerBeanDefinitions方法将Document资源委托给DefaultBeanDefinitionDocumentReader,DefaultBeanDefinitionDocumentReader调用parseBeanDefinitions方法对Document资源的各个节点 进行解析并注册。
  • 注册主要是DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法中调用了BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法对Document的节点解析成BeanDefinitionHolder,BeanDefinitionHolder中封装了beanName、BeanDefinition、Aliases等属性。
  • 然后调用DefaultListableBeanFactory核心类的registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())方法完成BeanDefinition的向ioc容器注册,ioc容器就是以DefaultListableBeanFactory内部的一个ConcurrentHashMap作为存储存储媒介

单例bean的加载创建:

AbstractBeanFactory类getBean方法中的doGetBean这个方法蕴含了整个bean的依赖注入、bean的创建、属性赋值、初始化、后置处理器的前后置方法的调用、循环依赖解决等。
doGetBean方法主要有两个分支,分支一:从缓存取bean,分支二:缓存中不存在bean,从头开始创建bean

从缓存取bean
  • doGetBean中先通过getSingleton(beanName)获取缓存中的对应beanName的原始对象,然后调用getObjectForBeanInstance方法对应原始对象进行还原,创建出来的bean都要经过getObjectForBeanInstance方法才能完成创建,原因是创建出来的bean可能是一个factorybean工厂对象,所以需要调用此方法,内部会判断如果是一个factorybean,就会调用其getObject方法还原bean,还原后直接返回
  • 为解决单例模式的循环依赖,在spring创建bean的时候是不等bean创建完成就将创建的objectFactory提前曝光加入缓存中,一旦下一个bean创建需要依赖上一个bean的时候则直接使用objectFactory
    getSingleton 方法涉及了spring的三级缓存:
    singletonObjects:第一级缓存,存放可用的完全初始化,成品的Bean。存放的是beanName与bean实例
    earlySingletonObjects:第二级缓存,存放半成品的Bean,半成品的Bean是已创建对象,但是未注入属性和初始化。用以检测循环依赖。这里主要是存放的是beanName与正在创建的bean实例,用来检测循环依赖
    singletonFactories:第三级缓存,存的是Bean工厂对象,用来生成半成品的Bean并放入到二级缓存中。用以解决循环依赖。如果Bean存在AOP的话,返回的是AOP的代理对象。存放的是beanName与objectFactory,这是解决循环依赖的主要手段
从头开始创建bean
  • 先判断是否是多例并且存在循环依赖,是则抛出异常,不处理
  • 查找ioc容器中是否包含这个bean,不包含则需要从父类容器中getBean方法创建bean
  • ioc容器中存在此beanName的BeanDefinition,则将此BeanDefinition及其父类的属性合并成RootBeanDefinition
  • 使用RootBeanDefinition.getDependsOn()方法查找这个bean创建需要依赖的对象,先遍历这些属性调用getBean创建这些依赖对象
  • 从RootBeanDefinition判断这个bean是单例还是多例,单例则使用,以下代码创建
//这个getSingleton和上面的getSingleton不一样,是个重载的getSingleton方法 
sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

这里的getSingleton主要是使用匿名函数createBean创建的objectFactory然后调用getObject完成bean的创建初始化,然后将创建好的bean实例singletonObjects一级缓存中, 然后调用getObjectForBeanInstance对原始对象进行还原

  • 这其中createBean是AbstractAutowireCapableBeanFactory的方法,在方法中会调用resolveBeforeInstantiation返回代理做前置处理,如果这个方法返回的bean不为空,则说明bean对象是代理使用前置处理生成的beanbean,不需要容器做后续的创建工作
  • 如果resolveBeforeInstantiation方法返回的是空对象,那么就需要使用doCreateBean进行创建了,doCreateBean方法是蕴含了bean对象的实例化、属性赋值、实例化的一系列生命周期的方法,其中夹杂了许多前后置的处理调用,这个方法非常关键
单独分析doCreateBean方法

doCreateBean也是AbstractAutowireCapableBeanFactory的方法,是bean进行常规创建的方法。

  • bean的实例化。先使用createBeanInstance方法进行bean的实例化,这是bean生命周期的第一个阶段,里面包含里多种实例化策略,包括了工厂方法、构造函数自动注入、简单初始化等,具体的逻辑是,如果BeanDefinition中包含工厂方法优先使用工厂方法实例化、否则spring会更加参数去锁定使用bean中的哪一个构造方法,如果不是工厂方法也不存在带参数的构造方法,则使用默认是无参构造进行实例化,实例化的bean是以BeanWrapper类型存在,BeanWrapper封装了bean各类消息,通过BeanWrapper.getWrappedInstance返回实例化的bean。
  • 调用完createBeanInstance实例化完bean后,然后spring为了解决循环依赖,会在完成bean创建前调用addSingletonFactory方法,将objectFactory放入三级缓存中,以此解决循环依赖。objectFactory是通过实例化的bean实例去生成的。
  • 这里我们单独说一下spring如何解决循环依赖,spring调用了我们刚刚提到的addSingletonFactory方法,代码如下:
//mbd是RootBeanDefinition,bean是BeanWrapper调用getWrappedInstance()返回的刚刚实例化的bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

我们在看看里面的匿名函数:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
                exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
        return exposedObject;
    }

这里使用了SmartInstantiationAwareBeanPostProcessor的后置处理器的调用,对bean进行处理,aop将advice动态织入也是在这里实现的,也就是基于SmartInstantiationAwareBeanPostProcessor类实现的动态织入,spring如何使用其解决循环依赖依赖的呢?假如此时A创建时需要创建B,B创建时需要A,而此时通过提供objectFactory来填充B的依赖属性A,因为A是正在创建进行中,只进行了实例化,没有进行任何的属性赋值,但是objectFactory就是在此方法中通过刚刚实例化的A的实例bean生成的,所以此objectFactory指向的属性地址是与B中持有的A是一样的,B也只是仅仅需要A类型的属性赋值以便完成创建而已,所以A能填充到B中,这样就解决了循环依赖。这仅仅只是getset方法注入及单例才能解决的循环依赖。如果是构造器注入的话是没有办法解决循环依赖的,原因是A构造器注入时需要一个创建好的B,B构造器注入时需要一个创建好的A,因此A和B没办法实例化,提供一个A或者B属性的对象,这样就没有办法解决循环依赖。但是getset注入就可以使用无参构造一个bean,所以能做到完成属性赋值等一系列操作前暴露一个使用构造好的bean创建的objectFactory去解决循环依赖,并不需要完成创建好。多例模式无法解决循环依赖的是因为bean每次使用时都需要创建一个最新的对象,对象没办法进行复用所以容器不会进行缓存,就无法提前暴露一个bean。
当面试官提问spring如何解决循环依赖时可以这么会答:在单例模式getset注入的情况下,spring的创建bean的过程中,bean进行实例化后会暴露一个objectFactory并存入三级缓存中,在还没有完成bean的创建完成前会使用三级缓存解决循环依赖的问题,完成bean的创建后就会将对应的三级缓存移除,并存入一级缓存,以便下次使用时可以复用

  • bean的属性赋值,回到doCreateBean方法调用完addSingletonFactory方法之后会使用populateBean方法对bean进行属性赋值,这是bean生命周期的第二个阶段,详细过程是从RootBeanDefinition获取PropertyValues对象,根据条件决定调用autowireByName方法按名称调用还是autowireByType按类型注入,无论是按名称注入还是按类型注入都是根据RootBeanDefinition和BeanWrapper去查找需要注入的依赖bean,然后对这些bean进行循环遍历并调用getBean方法一一创建依赖对象,将依赖对象存储到PropertyValues中,变量后置处理器对PropertyValues中的依赖属性进行后置处理,然后调用applyPropertyValues方法将PropertyValues设置的依赖对象应用到已经实例化好的bean到中,这样就完成了bean的属性赋值
  • bean的初始化,回到doCreateBean方法继续调用initializeBean去完成bean生命周期的第三个阶段:初始化此时bean已经完成了实例化以及属性赋值,这时就会调用用户设定的初始化方法。方法中调用invokeAwareMethods这个方法会调用一系列的xxxxAware类的方法,applyBeanPostProcessorsBeforeInitialization是遍历postPostProcessor的前置方法并调用,applyBeanPostProcessorsAfterInitialization是遍历postPostProcessor的后置方法并调用。
  • 初始化完成后返回实例对象,然后返回到doGetBean方法中,将其传入getObjectForBeanInstance方法将bean进行还原,然后返回

这就是单例bean创建的大概过程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章