springboot web 启动后为什么不会停止
jls 12.8 中 jvm终止需要满足以下两个任意一个:
All the threads that are not daemon threads terminate. (全部非守护进程终止)
Some thread invokes the exit method of class Runtime or class System, and the exit operation is not forbidden by the security manager.(主动调用exit且未被拦截)
springboot web 运用了第一种
如何确定有哪些非守护进程呢?可以利用ThreadMXBean
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); System.out.println("线程:" + threadMXBean.getDaemonThreadCount() + "/" + threadMXBean.getThreadCount()); long[] allThreadIds = threadMXBean.getAllThreadIds(); String s = "%s\t%s\t%s\t%s"; System.out.println("线程名称\t是否守护\t状态\t线程ID"); for (long l : allThreadIds) { ThreadInfo threadInfo = threadMXBean.getThreadInfo(l); System.out.println(String.format(s, threadInfo.getThreadName(), "?",threadInfo.getThreadState(),threadInfo.getThreadId())); }
线程:19/25
spring 启动时会判断classpath下是否有特定的类,来决定是servlet 、reactive还是普通应用,进而决定ApplicationContext 是哪种
此例中依赖embed tomcat ,springboot ApplicationContext 实例是 org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
org.springframework.boot.SpringApplication.run(Class<?>, String...) org.springframework.boot.SpringApplication.run(Class<?>[], String[]) org.springframework.boot.SpringApplication.run(String...) org.springframework.boot.SpringApplication.refreshContext(ConfigurableApplicationContext) org.springframework.boot.SpringApplication.refresh(ApplicationContext) org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh() org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh() org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer() org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(ServletContextInitializer...) org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(Tomcat) org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize() org.springframework.boot.web.embedded.tomcat.TomcatWebServer.startDaemonAwaitThread() org.apache.catalina.core.StandardServer.await()
private void startDaemonAwaitThread() { Thread awaitThread = new Thread("container-" + (containerCounter.get())) { @Override public void run() { TomcatWebServer.this.tomcat.getServer().await(); } }; awaitThread.setContextClassLoader(getClass().getClassLoader()); awaitThread.setDaemon(false); awaitThread.start(); }
这里可以看到,tomcat server 启动了一个非守护进程,run方法中是循环等待,只有满足循环中断条件该线程才会结束
await 方法的注释也进一步佐证
/** * Wait until a proper shutdown command is received, then return. * This keeps the main thread alive - the thread pool listening for http * connections is daemon threads. */ @Override public void await() {...}