这是我参与更文挑战的第1天,活动详情查看: 更文挑战
前面的文章主要写了spring源码工厂后置处理器所干的事情,即spring工程的扫描,解析,得到beanDefinition以及所有的beanName,还有注解
@Import
的原理,以及引入ImportSelector
和ImportBeanDefinitionRegistrar
的应用,有兴趣的可以看看前面的文章。这篇文章开始写bean的实例化过程,读源码比较枯燥,相关的文章也比较枯燥,我尽量写简单明了点。
1.概述
上面的图大概画了整个bean的创建流程,spring在创建bean之前首先从缓存池中去getBean,当从缓存池中获取不到bean时,才会去创建bean。了解spring源码的同学知道,spring中有三级缓存:
- 一级缓存:singletonObjects —> 存放完整bean的单例池
- 二级缓存:earlySingletonObjects —> 存放非完整bean的单例池,存放早期暴露的bean
- 三级缓存:singletonFactories —> 存放可以创建bean的factory,这里的factory主要是去创建bean的代理对象
在创建bean的过程中,会通过bean后置处理去拿到bean的构造方法,对bean进行创建,然后对bean进行包装代理,如果bean不需要进行包装代理,就会返回一个早期暴露的对象,并放入二级缓存中,如果需要进行包装代理,就会返回一个factory,并放入三级缓存中。
然后会组装bean,这个过程就是去装配bean的属性,当bean装配完成后,bean就算是一个完整的bean了,最后会把这个完整的bean放入单例池中,即一级缓存中。
这就是bean创建的整个过程,这里概述了一下,也是想读到这篇文章的同学心里有一个大概,后面不至于晕乎乎的,下面就进入源码阅读阶段吧。
2.从缓存池中getBean
我们直接看doGetBean()这个方法,方法路径:AbstractBeanFactory#doGetBean()
,在该方法最开始的时候就是去从单例池获取bean:
接下来就点进这个方法看看是怎么从缓存中获取bean的:
可以看到代码中,首先是从一级缓存中去拿bean,当拿不到bean时,且当前bean正在被创建,就会从二级缓存中去获取,当二级拿不到时,从三级缓存中获取factory对象,如果拿到了factory对象,会从factory中去获取bean,最后将该bean放入二级缓存中。
由于spring工程在启动时,缓存里肯定没有bean对象,于是就需要去创建bean,接下来看bean是如何创建的。
3.bean的创建
还是doGetBean()方法,看一下最重要的代码片段:
这里有两个方法,先看方法1,即createBean(beanName, mbd, args);
点进这个方法去看看,这里省略了一些不重要的代码:
1 | java复制代码protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) |
可以看到这段代码片段里,首先是去处理overrides,然后去调用一个bean后置处理(InstantiationAwareBeanPostProcessor
)的方法,如果该方法返回了一个对象,则返回该对象,不进行后面的bean创建流程。
接下来看看创建对象这个方法:Object beanInstance = doCreateBean(beanName, mbdToUse, args);
在这个方法里,我们一部分一部分的来看,第一部分就是去创建bean对象:
来看看创建包装对象的部分,点进这个方法中:instanceWrapper = createBeanInstance(beanName, mbd, args);
依然省略一部分不重要的代码:
1 | java复制代码protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { |
该方法主要是讲如何去创建bean,首先是通过supplier的方式实例化对象,其次是通过FactoryMethodName的方式去实例化对象(这种方式好像没用过,有大神知道吗),再然后是通过bean后置处理器去找到bean的构造方法,如果bean中定义了有参构造方法,就返回有参构造方法,determineConstructorsFromBeanPostProcessors(beanClass, beanName);
这里面有一些逻辑,感兴趣的同学可以自己去看一看,如果没有找到有参构造方法,就返回默认的无参构造方法。到这里就返回了一个BeanWrapper对象。
4.代理bean,放入三级缓存
前面bean已经被实例化出来了,因为spring中有些对象需要被代理,来看看这段代码:
在getEarlyBeanReference(beanName, mbd, bean));
这个方法里,实际上就是去执行bean后置处理器中的方法,对bean进行代理:
1 | java复制代码Object proxy = createProxy( |
最后会调用 ProxyFactory#getProxy
方法:
这里是不是就是我们熟悉的JDK代理和Cglib代理~
然后看 addSingletonFactory()
这个方法:
1 | java复制代码protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { |
这里就是将factory对象放入三级缓存中。
5.组装bean,循环依赖问题
这里就不贴代码了,感兴趣的同学下来再研究吧。这里就是对bean的属性进行填充,比如A依赖B,这里就是去填充B.
这里涉及到一个很经典的问题,就是spring中的循环依赖问题,spring到底是怎么解决循环依赖问题的呢?
我在读spring源码后,画了一张图,来清晰的表示:
假设A和B相互依赖,当创建A到了组装这一步骤时,需要去组装B,这个时候就会去getB,但是get不到,就会去创建B,当创建B到组装这一步骤时,需要去组装A,而A这个bean已经创建过了,并且在缓存中,可以得到A,这个时候B就组装完成了,而当B组装完成了,相应的A也组装完成。
最后A和B都是一个完整的bean,然后被放入一级缓存中,即单例池中。
到这里bean的整个创建过程和spring的循环依赖问题就讲完了,希望看到这篇文章的同学有所收获。
本文转载自: 掘金