spring-boot源码分析之beanFactory · 玖

云中志

共 2799字,需浏览 6分钟

 · 2021-09-17

前言

今天我们开始看refresh的最核心方法,这四个方法剖析完成,spring boot就真的启动成功了:

  • onRefresh
  • registerListeners
  • finishBeanFactoryInitialization
  • finishRefresh

refresh

onRefresh

这个方法就是初始化特殊子类容器中的特殊bean,这个方法的具体调用流程如下:

首先它先调用了abstractApplicationContextonRefresh方法,由于这个是个抽象类,所以实际上调用的是当前容器或者其父类继承了abstractApplicationContext的类的onRefresh方法,实现onRefresh的类总共有5个:

但其中只有ServletWebServerApplicationContext是我们当前容器的父类,所以实际上最后调用的是ServletWebServerApplicationContexonRefresh方法,在它的方法内部有两部分调用,一个是调用父类的onRefresh方法,父类的方法内部其实就是进行了themeSource资源的初始化;另一部分,调用了createWebServer方法,顾名思义,就是创建web服务器。

initThemeSource

先看父类onRefresh的调用,它的内部其实就是进行了主题资源的初始化,准确地说就是进行了实例化和赋值,最后将themeSource返回:

看了半天才搞明白,原来这里的themeSource指的就是主题资源,我还在纳闷spring boot为啥还需要主题(就是手机桌面这种主题),最后才发现原来是给消息资源使用,主要包括css、图片等资源:

createWebContext

这个方法就是为了创建webServer,这一点从名字就可以看出来:

默认情况下webServerservletContext都是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的预初始化操作,官方给的注释是实例化剩余的单例。

下面我们详细看下freezeConfigurationpreInstantiateSingletons,先看freezeConfiguration方法:

本以为这个方法内部实现很复杂,点进来才发现就两行代码,第一行将configurationFronzen设置为true,这个属性用于标记bean的定义元数据是否已经被缓存。

第二行是将bean定义名赋值给frozenBeanDefinitionNames,从名字推测这个应该是为了冻结bean定义名,这也就意味着在这个方法执行之后,不会再注册新的bean定义名。

下面我们看第四块的第三个方法——preInstantiateSingletons,这个方法主要有两大块内容,一块是实例化非懒加载的bean(通过getBean方法,看来我对这个方法理解的不够透彻,但是这个方法内部并没有进行newInstance这样的操作,而是直接从beanbeanFactory中获取);

另一块是初始化后,回调操作。这里的doPrivileged方法是java.security包下提供的一个特权操作,关于这一块后面需要深入研究下。这个doPrivileged内部调用了afterSingletonsInstantiated,这个方法在单例实例化完成后调用,就是我们说的回调操作

finishRefresh

这个方法就是完成最后的清理工作,同时会初始化容器的生命周期处理器,然后执行容器生命周期的刷新操作,最后会推送启动刷新完成事件

总结

紧赶慢赶,四个方法总算全部分享完了,差一点点就分析不完了,而且最后一个方法实在分析地有点拉垮。

总之,关于这两天的内容更新,我总结出来两点:

第一,周末效率有点低下,没玩好也没学好,特别容易被打扰,内容输出还是要找一个安静、舒适的环境,这样精力比较集中;

第二,spring boot真的上头呀。感觉run方法的核心代码都已经分析完了,但我咋发现,我好像还是没理清楚spring boot的启动流程呢?或者更准确的说是感觉目前分析的内容和我预期的是有差异的,而且差异很大,具体的差异感觉得等我把run方法整体分析完,再回过头来总结,才能得出结论。现在感觉好像懂了,但是又没完全懂,说不懂吧,整体的知识更清晰了,感觉还是很朦胧。

确实有点上头了,而且spring boot的类名和方法名还老长,经常比对方法名比对半天……说多了都是泪,怕不是有点走火入魔了吧,赶快结束吧,后面要慢慢花时间消化了……

- END -


浏览 6
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报