SpringApplication的run方法是否会执行两次?源码层面求证
SpringApplication.run() execute twice? Great question! This double execution happens because you're inadvertently triggering two different Spring Boot application startup paths at the same time—one for embedded container launches, and another for WAR deployment to an external Servlet container. Let's break it down:
1. First run: Embedded container startup via main() method
When you run your application's main method:
public static void main(String[] args) { SpringApplication.run(HppaApplication.class, args); }
Spring Boot spins up its embedded web container (usually Tomcat by default) as part of the full application context initialization. This call to run() handles everything: loading your Spring beans, configuring the container, and starting the server.
2. Second run: External Servlet container deployment via SpringBootServletInitializer
If your application is packaged as a WAR and deployed to an external Servlet 3.0+ container (like a standalone Tomcat), the container triggers the ServletContainerInitializer hook. Spring Boot's SpringBootServletInitializer implements this hook, and its onStartup method eventually calls createRootApplicationContext(), which includes this key line:
protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) { // ... other initialization code return run(application); }
This run() call re-initializes the Spring context, tailored specifically for the external container environment.
Why both paths are triggering at once?
The most common cause is that you're running both startup modes simultaneously:
- Maybe you launched the
mainmethod in your IDE, and also deployed the WAR to a local Tomcat instance in the same IDE session. - Or your build/run configuration is set up to execute the
mainmethod and deploy the WAR, leading to duplicate initialization.
How to fix it?
You don't need to remove either the main method or the SpringBootServletInitializer inheritance—they can coexist for flexibility. Just make sure you only trigger one startup path at a time:
- For local development with an embedded container: Run directly via the
mainmethod. The external container hook won't fire here, so only onerun()call happens. - For production deployment to an external container: Package as a WAR and deploy it. The
mainmethod won't be executed by the external container, so only theSpringBootServletInitializerpath runsrun()once. - In your IDE, double-check your run configurations to ensure you're not running both a "Java Application" (main method) and a "Tomcat Server" (WAR deployment) at the same time.
内容的提问来源于stack exchange,提问作者John Ziv

