My First deployment in Tomcat
Introduction
As a student diving into DevOps practices, I recently created a simple API using Spring Boot and JDK 23. The goal was to understand the deployment process on Apache Tomcat. This API, handles basic user data retrieval. It uses a GET request where you pass a user ID as a parameter to fetch corresponding user details.
While deploying the application, I encountered a challenge involving the ServletInitializer
class. After some troubleshooting, I found a simple solution, and this blog is about sharing that experience to help others who might face similar issues.
You can check out the code on https://github.com/Inigojeevan/SpringApi
Deployment Attempt on Tomcat
For deployment, I packaged the application as a WAR file to deploy it on an Apache Tomcat 10+ server.
Configured the application.properties
to set the context path:
server.servlet.context-path=/myapi
server.port = 8085
Created the WAR file:
mvn clean
mvn install
Deployed it to Tomcat by placing the WAR file in the webapps
directory.
Everything was fine until this, but then came this error.
The Problem: ServletInitializer
Conflict
Upon starting the Tomcat server, I encountered this error:
codeCaused by: java.lang.IllegalStateException: Failed to register 'filter errorPageFilterRegistration' on the servlet context. Possibly already registered?
This error pointed to a conflict during the registration of servlet filters in the application. After some investigation, I realized it was due to the ServletInitializer
class in my project. Here’s what my ServletInitializer
looked like:
class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(RestapiApplication.class);
}
}
The Solution: Removing ServletInitializer
The issue was that ServletInitializer
was causing duplicate servlet context registrations in the Tomcat environment. After removing the ServletInitializer
class and rebuilding the project, the deployment worked seamlessly.
Here’s what I did:
Deleted the
ServletInitializer
class.Rebuilt the WAR file:
mvn clean
Re-deployed the updated WAR to Tomcat.
The application started without errors, and I was able to access the API at:
http://localhost:8085/apideloy<war file name>/user?ID=1
Why ServletInitializer
Wasn’t Needed
In this case, Spring Boot 3.x and JDK 23 handled servlet initialization dynamically. My specific configuration didn’t require the manual bridge provided by ServletInitializer
. The class is typically needed when you want to deploy a WAR file and customize the servlet initialization process. However, in modern setups, especially with Tomcat 10+, it often works out-of-the-box.
Conclusion
This experience taught me that deployment, even for simple applications, is never just about writing code. It’s a process of understanding configurations, environments, and potential conflicts. By solving this ServletInitializer
issue, I gained a deeper appreciation for the intricacies of deploying Java applications and learned a lesson that will undoubtedly help me in my DevOps journey.
You can find the source code for this project on my https://github.com/Inigojeevan/SpringApi. Let me know your thoughts or share your experiences with Spring Boot and Tomcat deployments!
Happy coding! 🚀