Spring源码讲解(三)Spring中Bean的实例化和解决循环依赖问题
由于Spring源码过于庞大,文章中不会列出细节,须要大家花时间下去研究哦
spring中bean的实例化是从AbstractApplicationContext的finishBeanFactoryInitialization方法开始的,具体的链路是:
AnnotationConfigApplicationContext#refresh ->
AbstractApplicationContext#finishBeanFactoryInitialization ->
DefaultListableBeanFactory#preInstantiateSingletons
看下这个preInstantiateSingletons方法:
所以spring实例化bean其实就是一个getBean的操作,继续往下看链路:
AbstractBeanFactory#getBean ->
AbstractBeanFactory#doGetBean ->
doGetBean中先通过getSingleton方法从单例池中拿bean,如果拿到了,就说明已经创建好了,直接返回了。这个getSingleton方法中有一段相当重要的逻辑是用来解决循环依赖问题的。
isSingletonCurrentlyInCreation方法判断当前bean是否正在创建中,依据是一个singletonsCurrentlyInCreation的set中是否存在当前bean的名字。
singletonObjects是spring存放所有单例bean的一个map,所有构造好的bean都在这里,可以看到这里首先从singletonObjects中获取bean,第一次创建bean的时候这里肯定是没有的。isSingletonCurrentlyInCreation目前也是false,所以直接会返回空对象回去。
当返回空时,doGetBean方法会进else,最终是走向这里:
可以看到这里分了三种情况,单例bean;原型bean和其他bean的情况,我们这里只考虑单例bean的情况,其通过一个getSingleton方法获取到了bean,看下这个getSingleton方法:
这里做了三件事:
第一件是基于singletonObjects加了个同步锁,然后尝试再去取一次bean,当然如果取到了的话就直接返回了
第二件是如果没取到的情况下调用beforeSingletonCreation方法,这个方法就是往singletonsCurrentlyInCreation这个set中存放当前bean的名字,结合上面,那么这个时候这个bean就代表正在创建中了(因为还是没取到嘛,那就得走创建流程了)
第三件是通过singletonFactory#getObject方法去创建这个bean,这个singletonFactory对象其实是从外部传进来的一个lambda表达式,他的getObject方法其实就是外层的createBean方法,接下来看下这个createBean方法:
AbstractAutowireCapableBeanFactory#createBean ->
AbstractAutowireCapableBeanFactory#doCreateBean
此时整个bean的生命周期开始:
这里spring首先推断出构造方法,然后运用反射创建出对象,之后就是对这个创建出的原生对象进行各种BeanPostProcessor的处理,最终形成一个真正的bean。
走到这里的时候,就是spring解决循环依赖问题的时候,看下这个addSingletonFactory方法:
这里又涉及到了getSingleton方法中的三个cache,singletonFactory,对应的就是外部的lambda表达式getEarlyBeanReference方法。
getEarlyBeanReference方法中就对实例化的对象进行各种后置处理器处理最终成为一个bean。
结合之前的getSingleton方法。讲下如何解决循环依赖:
spring获取单例bean时存在三级的缓存:
cache1:singletonObjects,就是spring的单例池,这里取出的是真正的bean
cache2:earlySingletonObjects,这里存放的相当于是一个半成品的bean,从上面的getSingleton方法可以看出来,其put的是singletonFactories中的bean工厂创建出来的半成品bean,而这个创建bean的方法就是对应的getEarlyBeanReference方法!!
cache3:singletonFactories,其实是一个创建bean的工厂
想象一下循环依赖的场景(A依赖B,B依赖A):
1..当实例化A时,spring在执行addSingletonFactory方法时,会将生成A的bean工厂放到singletonFactorie这个map中,然后对A赋值的时候须要get对象B,然后实例化B,A的实例化过程中会将isSingletonCurrentlyInCreation设置为true。
2.B的实例化过程同A,然后须要赋值,去get对象A。
3.先去singletonObjects单例池中取A,这个时候A肯定是没有的,(因为当前过程源头就是从A来的,A也在实例化中)
4.因为isSingletonCurrentlyInCreation是true,所以会从earlySingletonObjects中去拿,也是空。
5.再从singletonFactories中取到创建Bean的这个Bean工厂,调用其getObject方法取到半成品A,然后放到earlySingletonObjects这个map中。
之后别的bean再须要取A的时候,如果A没创建好,就直接从earlySingletonObjects这个map中去取。