spring-boot源码分析之beanFactory · 玖
共 2799字,需浏览 6分钟
·
2021-09-17 16:35
前言
今天我们开始看refresh
的最核心方法,这四个方法剖析完成,spring boot
就真的启动成功了:
onRefresh
registerListeners
finishBeanFactoryInitialization
finishRefresh
refresh
onRefresh
这个方法就是初始化特殊子类容器中的特殊bean
,这个方法的具体调用流程如下:
首先它先调用了abstractApplicationContext
的onRefresh
方法,由于这个是个抽象类,所以实际上调用的是当前容器或者其父类继承了abstractApplicationContext
的类的onRefresh
方法,实现onRefresh
的类总共有5
个:
但其中只有ServletWebServerApplicationContext
是我们当前容器的父类,所以实际上最后调用的是ServletWebServerApplicationContex
的onRefresh
方法,在它的方法内部有两部分调用,一个是调用父类的onRefresh
方法,父类的方法内部其实就是进行了themeSource
资源的初始化;另一部分,调用了createWebServer
方法,顾名思义,就是创建web
服务器。
initThemeSource
先看父类onRefresh
的调用,它的内部其实就是进行了主题资源的初始化,准确地说就是进行了实例化和赋值,最后将themeSource
返回:
看了半天才搞明白,原来这里的themeSource
指的就是主题资源,我还在纳闷spring boot
为啥还需要主题(就是手机桌面这种主题),最后才发现原来是给消息资源使用,主要包括css
、图片等资源:
createWebContext
这个方法就是为了创建webServer
,这一点从名字就可以看出来:
默认情况下webServer
和servletContext
都是null
,所以会创建webServer
实例,默认情况下创建的是TomcatWebServer
的实例,创建完成后会往beanFactory
中注册webServer
的两个生命周期实例,一个是shutdown
,一个是startStop
,这两个生命周期主要是用来控制服务启停的。
registerListeners
这个方法就是注册监听器,而且方法注释上也写的很清楚:校验并注册监听器
内部实现也很简单,首先是往应用事件广播器中添加监听器;
然后还把监听器的beanName
注册进应用监听器的接收器(defaultRetriever
)列表中,而且这里注释的很清楚:这里不初始化FactoryBeans
;
最后是推送应用预刷新事件(也就是我们第陆部分的内容,这里的监听器是在prepareRefresh
方法中进行初始化的)
finishBeanFactoryInitialization
从名字就可以看出来,这个方法就是完成最后的beanFactory
初始化,方法注释也说的很清楚,会初始化剩余的单例bean
。
方法主要有四块内容,第一块是设置beanFacory
的转换服务,我就说这一块的代码咋看着有点眼熟,原来是在分析prepareContext
方法的时候,当时也有调用这个方法。
第二块是注册已经嵌入的配置值的解析器,这里是lambda
的写法,这注册的应该是对$Value{name}
这样的配置的解析器
第三块是获取加载时间织入器,但是有一点我有点看不懂,getBean
是有返回值的,这里也没有接收,所以这里调用只是为了校验?
第四块就是调用beanFactory
的三个方法,首先是调用setTempClassLoader
置为null
,官方给的注释是停止使用临时加载器;然后调用freezeConfiguration
方法,官方给的注释是仅获取bean
的定义元数据,不做其他操作;最后调用preInstantiateSingletons
方法,从方法名来看这个方法会进行单例bean
的预初始化操作,官方给的注释是实例化剩余的单例。
下面我们详细看下freezeConfiguration
和preInstantiateSingletons
,先看freezeConfiguration
方法:
本以为这个方法内部实现很复杂,点进来才发现就两行代码,第一行将configurationFronzen
设置为true
,这个属性用于标记bean
的定义元数据是否已经被缓存。
第二行是将bean
定义名赋值给frozenBeanDefinitionNames
,从名字推测这个应该是为了冻结bean
定义名,这也就意味着在这个方法执行之后,不会再注册新的bean
定义名。
下面我们看第四块的第三个方法——preInstantiateSingletons
,这个方法主要有两大块内容,一块是实例化非懒加载的bean
(通过getBean
方法,看来我对这个方法理解的不够透彻,但是这个方法内部并没有进行newInstance
这样的操作,而是直接从bean
的beanFactory
中获取);
另一块是初始化后,回调操作。这里的doPrivileged
方法是java.security
包下提供的一个特权操作,关于这一块后面需要深入研究下。这个doPrivileged
内部调用了afterSingletonsInstantiated
,这个方法在单例实例化完成后调用,就是我们说的回调操作
finishRefresh
这个方法就是完成最后的清理工作,同时会初始化容器的生命周期处理器,然后执行容器生命周期的刷新操作,最后会推送启动刷新完成事件
总结
紧赶慢赶,四个方法总算全部分享完了,差一点点就分析不完了,而且最后一个方法实在分析地有点拉垮。
总之,关于这两天的内容更新,我总结出来两点:
第一,周末效率有点低下,没玩好也没学好,特别容易被打扰,内容输出还是要找一个安静、舒适的环境,这样精力比较集中;
第二,spring boot
真的上头呀。感觉run
方法的核心代码都已经分析完了,但我咋发现,我好像还是没理清楚spring boot
的启动流程呢?或者更准确的说是感觉目前分析的内容和我预期的是有差异的,而且差异很大,具体的差异感觉得等我把run
方法整体分析完,再回过头来总结,才能得出结论。现在感觉好像懂了,但是又没完全懂,说不懂吧,整体的知识更清晰了,感觉还是很朦胧。
确实有点上头了,而且spring boot
的类名和方法名还老长,经常比对方法名比对半天……说多了都是泪,怕不是有点走火入魔了吧,赶快结束吧,后面要慢慢花时间消化了……