在前面两篇的文章中我们分析了从Main开始的启动过程和ApplicationContext的刷新过程。
1. 这还有一个小小的疑问:main函数都运行为了,为什么spring boot还能够运行呢?
针对这个问题,我们转换一下思路,为什么spring boot应用程序还在运行,那是因为jvm还没有推出,那什么情况下jvm会退出呢?
我们都知道: System.exit()
或Runtime.exit()
可以直接导致当前JVM退出。还有一种情况就是所有的非daemon进程完全终止。
那么我们可不可以猜测Spring Boot还能够继续运行的原因是由于还有非daemon进程没有终止?
那我们用jstack分析一下一个启动的spring boot线程 jstack 9818 |grep tid |grep -v daemon
在我的电脑上能够看到如下信息:
排除掉其中的GC和JVM线程,我们发现了一个奇怪的线程server,那我们看一下server的详细信息呢?
看到这么我们注意到最后一行NettyWebServer.run方法,我们跟进代码按一下这里面是什么呢?在此我们找到了我们用jstack看到的server线程的由来,通过方法名startDaemonAwaitThread可以知道我们启动一个非daemon的线程来等待关闭spring boot线程。这就是为什么main方法运行完了,spring boot程序还能欧股继续运行的原因。
扩展一下,因为我的程序是基于spring cloud gateway的,底层是用户netty实现的nio。所以这个会进入NettyWebServer。如果是一般基于tomcat的会进入TomcatWebServer,tomcat也有相应的代码:
在那怎么确实用户netty还是Tomcat或者undertow等webServer呢?从前面的启动过程中我们看到有这样的代码
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils