spring-boot源码分析之BeanFactory · 陆

云中志

共 2691字,需浏览 6分钟

 ·

2021-09-12 22:01

前言

从今天开始,我们要啃硬骨头了——refreshContext。这个方法就是我们一直在说的spring boot最核心的方法,这个方法执行完成后,spring boot基本上就初始化完了,剩下的方法就是推送启动事件,回调相关的监听器之类的,反正就是吃透refresh方法,基本上就可以宣告革命胜利了,换句话说,就是如果我们啃下这块硬骨头之后,spring boot启动这块我们就算彻底剖析完了,剩下的都是查漏补缺的小知识点了,搂草打兔子,顺手的事。

好了,大话就说这么多,下面我们开始干活~

refreshContext

容器的刷新首先是从refreshContext方法开始的,然后refreshContext方法内部会调用容器的refresh方法。

这里 refreshContext就做了两件事,一个是注册容器关闭钩子函数,另外一个就是刷新容器。

关闭钩子函数可以让我们更优雅地关闭spring boot容器,这一块后期也专门分享一次;刷新容器方法最终会调用容器的刷新方法,关于这个方法,我们之前已经分享过了,t它的作用就是刷新容器中的持久化资源,这里的资源包括xmljava配置、注解、配置文件、数据库等。

下面,我们就来详细看下它的内部实现。我们先看下它的调用流程:

从上面图中我们可以看出来,最终其实调用的是AbstractApplicationContextrefresh方法,这个方法内部比较长,总共调用了15个方法,下面我们就逐一剖析这些方法,不过工作日时间有限,今天可能也分享不了太多内容,具体视情况而定吧。

prepareRefresh

我们先说prepareRefresh方法,这个方法的作用就是为后面的刷新操作做准备,内部实现如下:

简单解释下它的执行流程:

  • 首先设置spring boot的启动时间,获取的是当前时间;

  • 然后分别设置closedactiveflasetrue,这两个属性都是原子类AtomicBoolean

  • 接着会根据日志设置等级输出日志,不过这里必须是begug级别才会输出,如果是trace等级的,则会输出更详细的日志信息。

  • 再然后,它会调用initPropertySources方法,这个方法的作用就是进行配置资源初始化初始化,我们等下详细剖析;

  • 再下面就是资源的校验,这块也需要展开分析

  • 最后是监听器和监听事件的赋值操作

initPropertySources

initPropertySources方法进行的就是property资源的初始化,当前容器并没有重写该方法:

由于 AbstractApplicationContextinitPropertySources 方法是空实现,而且AnnotationConfigServletWebServerApplicationContext并没有重写该方法,所以最后调用的是父类GenericWebApplicationContext的这个方法,父类的方法中最后调用的是ConfigurableWebEnvironment的配置资源初始化方法:

在方法内部,首先通过getEnvironment方法获取系统的环境设置,然后同获取到的环境设置进行配置资源初始化,其中servletConfig的入参直接为null

关于这里获取到的ConfigurableWebEnvironment,我们做一点点扩展补充,ConfigurableWebEnvironment主要的属性是profiles和资源解析器,这里的defaultProfiles表示spring boot的默认配置文件,activeProfiles表示spring boot启动时激活的配置文件,从下面截图也可以很清楚看出来:

关于profile文件,相比各位小伙伴应该都不陌生,在spring boot中我们的配置文件就叫profile,默认情况下的配置文件是application.*,文件类型可以是properties文件或者yaml文件,我们通常通过spring.profiles.active=@profileActive@(``yml`方式类似)指定需要激活的文件(环境配置)

获取完配置资源之后,会调用ConfigurableWebEnvironmentinitPropertySources方法,下面是initPropertySources方法的内部调用流程。在debug过程中,我发现默认情况下servletContextservletConfig都为空,所以replace方法实际并未执行。

validateRequiredProperties

这里校验是根据我们AbstractPropertyResolver解析器的requiredProperties属性进行判断的,如果存在为空的配置就会报错,说这个方法内部实现也很简单,流程也不是很复杂,就是一些简单的资源获取和空判断:

这里的requiredPropertiesenvironment有关,它是AbstractEnvironmentsetRequiredProperties方法中初始化的,关于这个方法的调用,等我们回头分析environment初始化的时候再来研究。

监听器赋值

prepareRefresh0方法的最后就是一些监听器集合的赋值操作,earlyApplicationListeners表示预刷新容器应用监听器集合(pre-refresh ApplicationListeners),applicationListeners表示当前容器监听器集合,earlyApplicationEvents就表示预刷新应用监听事件。

其实也就是监听器的初始化,代码也很简单,加上注释就很容器理解,我也就不再赘述了。

总结

今天效率有点低呀,一整天就搞定了一个方法,确实有些离谱,但是也没办法,今天事情确实比较多——今天我负责处理oncall问题,然后下午又开了三个多小时的会,下班那会还在排查处理线上问题,有点难呀~

不过,好在之前已经把今天的内容写的七七八八了,不然今天新内容就悬了……刚刚又看了下剩余的内容,明天应该可以搞定3个方法,然后还剩11个方法,后天4个,大后天4个,周一安排3个,完美,所以今天就先到这里吧~

- END -


浏览 34
点赞
评论
收藏
分享

手机扫一扫分享

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

手机扫一扫分享

分享
举报