You can deploy a servlet-based Spring application to an external Tomcat server without using web.xml to register it. For Spring Boot, the documented route is to build a WAR, extend SpringBootServletInitializer, and configure it with your application class. For a non-Boot Spring application, Spring Framework can discover a WebApplicationInitializer and let it register the servlet components in code.
Before changing the build, check the application’s Spring generation, Servlet API namespace, Java baseline, and target Tomcat version. In particular, Tomcat 9 uses the javax.* API generation while Tomcat 10 uses jakarta.*; a WAR built for one is not generally a drop-in deployment for the other.
Check compatibility before building the WAR
This procedure is for a Spring application using the Servlet stack. The Spring Boot traditional WAR deployment guide does not support WebFlux applications. Identify the Spring Boot or Spring Framework release and the Servlet API namespace used by the application, then match them to the target Tomcat release and its Java requirements. Use the documentation for your exact Boot release before copying dependency snippets: there is no single version recipe that safely covers every combination.
The difference between Tomcat 9 and Tomcat 10 is especially important. Apache’s Tomcat 9 migration guide identifies Servlet 4.0 support and Java 8 or later. Tomcat 10 introduced the breaking move from javax.* to jakarta.*; Apache says affected applications need recompilation against the new APIs. See the Tomcat 9 migration guide and Tomcat 10 migration guide for the relevant release details and migration options.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →#1 Best Overall
Deploy a Spring Boot application as a WAR
Spring Boot supports traditional deployment as well as more modern forms of deployment. For an external servlet container, the application must provide a WAR and a servlet initializer that tells Boot how to start the application. The official procedure is documented in Spring Boot’s Traditional Deployment guide.
1. Add the servlet initializer
Make the main application class extend SpringBootServletInitializer and override configure to return a builder configured with the application source:
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
Replace MyApplication with your application’s actual class. The initializer is the external-container entry point; the main method can remain if you also want to run the application in an embedded setup.
Rank #2
2. Configure the build to produce a WAR
For Maven, set the project packaging to war. Spring Boot’s parent configures the Maven WAR plugin for this flow. Mark the embedded Tomcat starter as provided so the external container supplies the servlet runtime:
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
For Gradle, apply the war plugin and declare the embedded container with providedRuntime. The Boot guide prefers providedRuntime over compileOnly because the provided runtime dependencies remain available on the test classpath.
plugins {
id 'war'
}
dependencies {
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}
These are structural examples, not universal dependency coordinates for every Spring generation. Keep the Spring Boot release and container dependency versions aligned with the project’s supported combination.
Rank #3
3. Build and deploy the artifact
Build the WAR using your project’s normal Maven or Gradle build, then deploy that artifact to the selected Tomcat instance using the container’s deployment procedure. If you also need to launch the same artifact with java -jar, Spring Boot’s build tools can package provided dependencies under lib-provided, allowing the WAR to be used both as an executable archive and in a servlet container.
Register components in code in a non-Boot Spring application
You do not need Spring Boot to avoid web.xml. Spring Framework provides SpringServletContainerInitializer, a Servlet ServletContainerInitializer discovered through the spring-web JAR’s service-provider configuration. The servlet container invokes it at startup; it finds implementations of WebApplicationInitializer and delegates the ServletContext to them.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
A WebApplicationInitializer can register a DispatcherServlet, context listener, filters, and other Servlet API features programmatically. This is the core non-Boot mechanism for replacing descriptor-based registration. See the Spring Framework 7.0.9 API documentation for SpringServletContainerInitializer for the discovery and delegation behavior.
Replace only the registrations that were in web.xml
When migrating an existing application, separate component registration from other descriptor settings rather than assuming all XML configuration must disappear.
- Servlets: In a Spring Boot application, register servlet components through Spring configuration, including
ServletorServletRegistrationBeanwhere appropriate. - Filters: Use Spring configuration, such as
FilterorFilterRegistrationBean, when replacing filter declarations. - XML application contexts: Existing Spring XML resources can be imported with
@ImportResource; this does not makeweb.xmlthe registration mechanism.
Keep any remaining descriptor settings under review. A web.xml file can still affect startup discovery even if servlet registration is handled in code.
Check descriptor settings that can block initializer discovery
Servlet metadata and fragment ordering can change which startup components the container scans. Spring’s initializer documentation notes two settings to check when code-based initialization works in one environment but not another:
metadata-completecontrols Servlet annotation scanning.<absolute-ordering>controls which web fragments participate inServletContainerInitializerscanning. If absolute ordering is used, include Spring’s web fragment for the Spring initializer path to be discovered.
These settings do not mean web.xml is required for Spring registration; they explain why a retained descriptor can still influence discovery.
Do not confuse external WAR startup with embedded startup
The external-container WAR path and embedded-server initialization are different. Spring Boot’s Servlet Web Applications reference says embedded servlet containers do not directly execute ServletContainerInitializer or Spring WebApplicationInitializer. For embedded servlet-context setup, register a ServletContextInitializer bean instead. That embedded-server rule does not replace the SpringBootServletInitializer mechanism used for traditional WAR deployment.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

