一、日志现象
- 控制台最后一句是
Started TttttApplication in 0.24 seconds …
紧接着 JVM 正常退出:Process finished with exit code 0。 - 没有 ERROR/FATAL 日志,也没有 Spring Boot 的 banner 关闭、SpringApplicationShutdownHook 等典型异常信息。
=> 这说明Spring Boot 容器本身启动成功,但随后主线程无事可做,立即退出,因此 JVM 也跟着结束。
对 Spring Boot 应用来说,这通常意味着没有任何非守护线程在运行——最常见的原因就是没有内嵌 Web 容器。
二、根因定位
Spring Boot 3.x 只有在类路径下能找到 spring-boot-starter-web(或 spring-boot-starter-webflux) 时,才会自动配置并启动 Tomcat/Jetty/Undertow。
而你的启动命令里只依赖了:
/Users/…/spring-boot-starter-3.5.4.jar
并没有看到 spring-boot-starter-web 相关 jar。
因此 Spring Boot 启动后认为“这是一个非 Web 应用”,main 线程执行完 SpringApplication.run()
就直接返回,JVM 随之退出。
三、解决方案(任选其一)
你其实想做一个 Web 应用
在pom.xml
(或 Gradle)里加依赖:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
重新编译运行,控制台会多出:
Tomcat started on port(s): 8080 …
应用就会一直运行,等待 HTTP 请求。你确实只想做一个 命令行/批处理/定时任务 应用
让主线程不退出即可,常见做法:- 使用 Spring Boot 的
CommandLineRunner
/ApplicationRunner
,在里面跑一个长任务或死循环; - 或者显式阻塞主线程:
public static void main(String[] args) { ConfigurableApplicationContext ctx = SpringApplication.run(TttttApplication.class, args); // 阻塞等待关闭信号 ctx.getBean(ApplicationReadyEvent.class); }
- 也可以引入
spring-boot-starter-batch
/spring-boot-starter-integration
等框架,它们会自己维持线程池。
- 使用 Spring Boot 的
其他可能踩坑点(但本次日志未体现)
- main 方法写错:把业务代码放在
main
方法里,导致run()
返回后立即结束 —— 把业务逻辑放到@SpringBootApplication
之外的 Bean 里即可。 - 端口冲突:如果出现
Web server failed to start. Port 8080 was already in use
,换一个端口或在application.properties
里配置server.port=8081
即可。 - 低版本 JDK 不兼容:Spring Boot 3.5 要求 Java 17+,你用的是 21,没问题。
- main 方法写错:把业务代码放在
四、结论
这次“启动失败”并不是异常,而是没有 Web 依赖导致 JVM 正常退出。
尝试之后成功解决