Spring Boot应用启动两次问题咨询(含Servlet与Eh-Cache模块)
Spring Boot应用启动两次的解决方案
嘿,作为经常帮Spring Boot新手排查问题的开发者,你的这个启动两次的场景我太熟悉了!结合你给出的代码(继承了SpringBootServletInitializer,同时有@SpringBootApplication等注解),我来帮你分析原因和给出具体解决办法:
为什么会启动两次?
你当前的启动类同时承担了两个角色:
- 作为内嵌容器启动入口:通过
main方法调用SpringApplication.run()启动内嵌Tomcat/Jetty - 作为WAR部署入口:继承
SpringBootServletInitializer,让外部Servlet容器(比如Tomcat)能加载Spring Boot应用
当你在IDE中直接运行启动类,或者打包部署时,如果两种启动逻辑被同时触发,就会导致应用初始化两次(你看到的日志会打印两次"Welcome to Application")。另外,@ServletComponentScan本身不会导致启动两次,但如果和Servlet容器的扫描逻辑叠加,可能会加重问题,但核心原因还是启动类的双重角色。
具体解决方案
1. 拆分启动类(最推荐的方案)
把内嵌容器启动和WAR部署的逻辑拆成两个独立的类,避免冲突:
主启动类(用于内嵌容器启动)
@EnableCaching @SpringBootApplication @ServletComponentScan public class Application { private static final Logger log = LoggerFactory.getLogger(Application.class); public static void main(String[] args) { SpringApplication.run(Application.class, args); } public Application() { log.info("------------------------------"); log.info(" Welcome to Application"); log.info("------------------------------"); } }
独立的Servlet初始化类(仅用于WAR部署)
public class ServletInitializer extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { // 指向主启动类 return application.sources(Application.class); } }
这样拆分后:
- 直接运行
Application的main方法时,只会启动内嵌容器,不会触发SpringBootServletInitializer的逻辑 - 打包成WAR部署到外部容器时,容器会加载
ServletInitializer,启动Spring Boot应用,不会走main方法
2. 检查IDE运行配置
如果你是在IDE(比如IDEA/Eclipse)中运行,确保没有同时配置两种启动方式:
- 不要同时运行
Application的Java Application配置,又把WAR包部署到IDE内嵌的Tomcat中 - 只选择一种启动方式:要么直接运行
main方法(用内嵌容器),要么打包WAR部署到外部容器
3. 排除内嵌容器(如果仅做WAR部署)
如果你的应用只打算部署到外部Servlet容器,完全不需要内嵌容器,可以在依赖中排除内嵌Tomcat/Jetty,避免启动时的冲突:
Maven示例:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <!-- 添加Servlet API依赖(编译时生效,容器运行时提供) --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency>
Gradle示例:
dependencies { implementation('org.springframework.boot:spring-boot-starter-web') { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } providedRuntime 'javax.servlet:javax.servlet-api:4.0.1' }
验证方法
修改后启动应用,观察日志是否只打印一次"Welcome to Application",同时检查Servlet和EhCache的初始化是否正常,确保没有重复创建Bean的情况。
内容的提问来源于stack exchange,提问作者Boss
相关产品推荐
相关产品推荐

