How Spring Boot Starts Embedded Tomcat: From Main Method to Tomcat Lifecycle
This article explains how Spring Boot automatically starts an embedded Tomcat server, detailing the main entry point, context creation, refresh process, and the internal Tomcat components that are instantiated and started during application startup.
Spring Boot simplifies Java web development by providing an embedded Tomcat server that starts automatically, eliminating the need for external XML configuration.
During development the embedded Tomcat is sufficient, while in production many teams package the application as a WAR and deploy to an external Tomcat. To do this the embedded Tomcat starter must be excluded and the servlet API added.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>The main entry point of a Spring Boot application is a class annotated with @SpringBootApplication that calls SpringApplication.run() . When deploying as a WAR the class extends SpringBootServletInitializer and overrides configure() to supply the source.
@SpringBootApplication
public class MySpringbootTomcatStarter extends SpringBootServletInitializer {
public static void main(String[] args) {
Long time = System.currentTimeMillis();
SpringApplication.run(MySpringbootTomcatStarter.class);
System.out.println("===应用启动耗时:" + (System.currentTimeMillis() - time) + "===");
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(this.getClass());
}
}The SpringApplication.run() method ultimately creates a ConfigurableApplicationContext , prepares the environment, creates the application context, and refreshes it. The refresh step is where the embedded Tomcat is instantiated.
public static ConfigurableApplicationContext run(Class
primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class
[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
public ConfigurableApplicationContext run(String... args) {
ConfigurableApplicationContext context = null;
// ... omitted for brevity ...
context = this.createApplicationContext();
// ... omitted for brevity ...
this.refreshContext(context);
// ... omitted for brevity ...
return context;
}Creating the context involves selecting an appropriate ApplicationContext implementation based on the WebApplicationType . For a servlet application Spring Boot uses AnnotationConfigServletWebServerApplicationContext , which extends ServletWebServerApplicationContext and ultimately AbstractApplicationContext .
protected ConfigurableApplicationContext createApplicationContext() {
Class
contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException ex) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}During the refresh, AbstractApplicationContext.refresh() invokes several lifecycle methods, including onRefresh() of ServletWebServerApplicationContext . This method creates a WebServer via a ServletWebServerFactory implementation; for Tomcat the class is TomcatServletWebServerFactory .
protected void onRefresh() {
super.onRefresh();
try {
this.createWebServer();
} catch (Throwable ex) {
// handle exception
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = this.getWebServerFactory();
this.webServer = factory.getWebServer(this.getSelfInitializer());
} else if (servletContext != null) {
this.getSelfInitializer().onStartup(servletContext);
}
this.initPropertySources();
}The TomcatServletWebServerFactory.getWebServer() method constructs a Tomcat instance, configures a Connector , sets the base directory, and prepares the engine hierarchy (Engine → Host → Context → Wrapper). It then returns a TomcatWebServer wrapper.
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, getPort() >= 0);
}The TomcatWebServer starts the embedded server by invoking tomcat.start() , which starts the underlying Server and its services. It also registers a shutdown hook and logs the ports on which Tomcat is listening.
public void start() throws WebServerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
try {
addPreviouslyRemovedConnectors();
Connector connector = this.tomcat.getConnector();
if (connector != null && this.autoStart) {
performDeferredLoadOnStartup();
}
checkThatConnectorsHaveStarted();
this.started = true;
logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '" + getContextPath() + "'");
} catch (ConnectorStartFailedException ex) {
stopSilently();
throw ex;
} catch (Exception ex) {
throw new WebServerException("Unable to start embedded Tomcat server", ex);
} finally {
Context context = findContext();
ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
}
}
}In summary, Spring Boot launches an embedded Tomcat during the application context refresh by creating a Tomcat object, configuring its connectors and engine, and then starting the server. Understanding this flow helps developers customize the startup process or replace Tomcat with Jetty or Undertow.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.