My First deployment in Tomcat

·

3 min read

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:

  1. Deleted the ServletInitializer class.

  2. Rebuilt the WAR file:

     mvn clean
    
  3. 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! 🚀