SpringBoot项目启动过程源码终于整体捋了一遍(完结)

时间:2024-04-10 19:05:50

上篇看到了refreshContext()方法:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

refresh()分析完了,接下来看一下这个shutdownHook,撸源码之前先介绍一下它。

我们做开发的经常需要考虑服务宕机的情况,OOM内存溢出也好,断电断网也好,甚至用户直接点了叉强制退出了。如果服务正在进行很重要的操作处理很重要的数据这个时候进程挂掉了,那之前的活岂不是白干了,甚至还会导致系统bug。所以这个时候我们希望在服务宕机之前能给我们机会做一些补救措施,比如把处理一半的数据保存下来或者销毁之类啊,java还真提供了这种机会,就是添加钩子函数。

代码核心就一句:Runtime.addShutDownHook(Thread hook),写了一个例子看一下:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

这里出现异常线程挂掉之前执行了hook thread。如果没有异常呢:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

可以看到没有异常的话线程执行完退出之前也会执行这个hook thread。看来钩子里重写的run()方法中,我们要自己判断是否需要执行补救措施,线程正常执行完就不需要什么补救措施了嘛。Spring添加钩子函数也很简单。ApplicationContext.registerShutdownHook();这一行代码就行了,当然里面停机前的逻辑也是人家写好的。

这个shutdownHook用法大致就这介绍完了,继续撸一下refreshContext()方法的源码,先是判断this.registerShutdownHook这个布尔型变量,如果是真的话执行了context.registerShutdownHook();哈好眼熟,这不就是刚说的Spring添加钩子函数的方法嘛,看来Spring boot添加钩子函数还有一个方法,就是设置这个this.registerShutdownHook:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

而且这个this.registerShutdownHook是默认为true的,也就是说Spring Boot默认是添加的优雅停机的钩子函数的,看一下这个registerShutdownHook()方法:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

这就和刚刚介绍的钩子函数的例子对上了,主要看doClose()方法,看看spring在宕机前做了什么事,方法就不贴了,感兴趣的可以去看一下,主要就是bean的destroy和Spring容器的关闭,这样做到平滑关闭。

到这里context三连的第二连refreshContext也看完了,再贴一下三连:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

 继续看afterRefresh():

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

就这?好吧,看来是留给自定义SpringApplication的时候重写用的。context三连就看完了,回到run()方法中:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

 继续往下看:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

这就是个计时的,第六篇提到过(https://blog.csdn.net/weixin_42447959/article/details/105263684),这里是stop计时停止了,然后把耗时通过启动日志打印出来。

继续往下看:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

又开始 发布事件了,这里发布的是ApplicationStartedEvent事件,关于事件发布机制第六篇(https://blog.csdn.net/weixin_42447959/article/details/105263684)有详细介绍。

继续往下看:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

看一下这个方法:

 

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

 先是加载Bean容器中ApplicationRunner和CommanLineRunner的子类,然后遍历执行重载的callRunner()方法:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

本质上就是把Bean容器中ApplicationRunner和CommanLineRunner的子类的run()方法都执行一遍,具体干了什么就要去看有哪些子类了,这里不多介绍。

跳过异常继续往下看:

SpringBoot项目启动过程源码终于整体捋了一遍(完结)

 这里是发布了ApplicationReadyEvent事件。

我的天!

虽然有点虎头蛇尾,不过算是终于撸完了,总结一下就是Sping Boot的启动过程中事件发布机制真的很重要,发布了一个事件有好几个监听执行了自己的逻辑,如果要把Spring Boot的启动过程弄得明明白白恐怕要把spring.factories里面的这些监听器都看一遍了,包括刚刚说的ApplicationRunner和CommanLineRunner的子类,这些都在Bean容器中。不过有了概念之后问题解决确实快了很多,都说学习是需要反馈的,最近撸这段源码的时间,自己工作上正好需要把一个Spring MVC+JSP的老项目用Spring Boot重构一下,说实话有些东西清晰好多,这段撸源码的反馈来的也太快了。