Skip to main content

Spring Tomcat Deployment

Introduction

Apache Tomcat is one of the most popular servlet containers for deploying Java web applications, including Spring applications. As a lightweight, open-source implementation of the Java Servlet, JavaServer Pages, and WebSocket technologies, Tomcat provides an excellent environment for running your Spring applications in production.

In this guide, we'll walk through the process of deploying Spring applications to Tomcat, covering everything from setting up your project structure to configuring and deploying your application on a Tomcat server.

Prerequisites

Before we begin, make sure you have:

  • Basic knowledge of Spring Framework
  • JDK 8 or higher installed
  • Apache Maven or Gradle build tools
  • Apache Tomcat installed (version 8.5, 9, or 10)

Understanding Spring Deployment Options

Spring applications can be deployed in different ways:

  1. Embedded Tomcat (common in Spring Boot applications)
  2. Traditional WAR deployment (what we'll focus on in this guide)

Setting Up Your Spring Application for Tomcat Deployment

Step 1: Configure Your Project as a WAR

Using Maven

For Maven, you need to specify war as the packaging type in your pom.xml:

xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>spring-tomcat-demo</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>

<!-- Other project configurations -->
</project>

Using Gradle

For Gradle, add the war plugin to your build.gradle:

groovy
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '2.7.0'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
}

Step 2: Create a Web Application Initializer

For a Spring MVC application, you'll need a class that implements WebApplicationInitializer to replace the traditional web.xml configuration:

java
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class MyWebAppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Create the Spring application context
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);

// Register the dispatcher servlet
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
"dispatcher", new DispatcherServlet(context));

dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}

Step 3: For Spring Boot Applications

If you're using Spring Boot, you need to extend SpringBootServletInitializer in your main class:

java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.boot.builder.SpringApplicationBuilder;

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Step 4: Mark Embedded Tomcat as Provided (for Spring Boot)

If you're using Spring Boot, you need to mark the embedded Tomcat as provided to avoid conflicts with the external Tomcat server:

In Maven:

xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>

In Gradle:

groovy
dependencies {
// ... other dependencies
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}

Building Your WAR File

Using Maven

Run the following command:

bash
mvn clean package

This will create a WAR file in the target directory.

Using Gradle

Run the following command:

bash
./gradlew clean build

This will create a WAR file in the build/libs directory.

Deploying to Tomcat

There are several ways to deploy your application to Tomcat:

Method 1: Manual Deployment

  1. Copy your WAR file to the webapps directory in your Tomcat installation.
  2. Start Tomcat (if it's not already running) using the startup.sh (Linux/Mac) or startup.bat (Windows) script in the bin directory.
  3. Tomcat will automatically unpack and deploy your application.

Example:

bash
# Stop Tomcat if it's running
$TOMCAT_HOME/bin/shutdown.sh

# Copy WAR file
cp target/spring-tomcat-demo-1.0.0.war $TOMCAT_HOME/webapps/

# Start Tomcat
$TOMCAT_HOME/bin/startup.sh

# Check logs for deployment status
tail -f $TOMCAT_HOME/logs/catalina.out

Method 2: Using Tomcat Manager

  1. Configure the Tomcat Manager by adding a user in $TOMCAT_HOME/conf/tomcat-users.xml:
xml
<tomcat-users>
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<user username="admin" password="password" roles="manager-gui,manager-script"/>
</tomcat-users>
  1. Access Tomcat Manager at http://localhost:8080/manager/html
  2. Use the "Deploy" section to upload and deploy your WAR file

Method 3: Using Maven Plugin

Configure the Tomcat Maven plugin in your pom.xml:

xml
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>tomcat-server</server>
<path>/myapp</path>
</configuration>
</plugin>

Then, add server credentials in your Maven settings.xml:

xml
<servers>
<server>
<id>tomcat-server</id>
<username>admin</username>
<password>password</password>
</server>
</servers>

Deploy with Maven:

bash
mvn tomcat7:deploy

Or redeploy if the application already exists:

bash
mvn tomcat7:redeploy

Common Deployment Configurations

Context Path Configuration

You can specify the context path (URL base path) for your application in several ways:

  1. WAR filename: The WAR file name becomes the context path by default. For example, myapp.war will be accessible at http://localhost:8080/myapp

  2. Using a context.xml file: Create a META-INF/context.xml file in your WAR:

xml
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/custom-path">
<!-- Additional configuration can go here -->
</Context>

JNDI Resources Configuration

You can configure database connections and other resources in Tomcat's context.xml:

xml
<Context>
<Resource name="jdbc/myDataSource"
auth="Container"
type="javax.sql.DataSource"
username="dbuser"
password="dbpass"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/mydb"
maxActive="20"
maxIdle="10"
maxWait="-1"/>
</Context>

Then reference it in your Spring configuration:

java
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() throws NamingException {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("java:comp/env/jdbc/myDataSource");
}
}

Troubleshooting Common Issues

ClassNotFoundException or NoClassDefFoundError

This usually happens when a dependency is missing from your WAR. Make sure all required libraries are included in WEB-INF/lib.

Solution: Check your dependencies and their scopes in the build file.

404 - Resource Not Found

This could happen if:

  • The context path is incorrect
  • Your servlet mappings are incorrect
  • Spring controllers are not properly configured

Solution: Check your application logs in $TOMCAT_HOME/logs for more details.

Tomcat Startup Errors

If Tomcat fails to start after deploying your application:

Solution:

  1. Check catalina.out log file
  2. Remove your application's WAR from the webapps directory
  3. Start Tomcat
  4. Fix the identified issues
  5. Redeploy

Real-world Example: Complete Spring MVC Application Deployment

Let's walk through deploying a simple Spring MVC application to Tomcat.

Project Structure

src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ ├── config/
│ │ │ ├── AppConfig.java
│ │ │ └── WebMvcConfig.java
│ │ ├── controller/
│ │ │ └── HomeController.java
│ │ └── Application.java
│ ├── resources/
│ │ └── application.properties
│ └── webapp/
│ ├── WEB-INF/
│ │ └── views/
│ │ └── home.jsp
│ └── META-INF/
│ └── context.xml
pom.xml

Application Configuration

AppConfig.java

java
package com.example.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.example")
public class AppConfig {
// Bean definitions
}

WebMvcConfig.java

java
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {

@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}

HomeController.java

java
package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

@GetMapping("/")
public String home(Model model) {
model.addAttribute("message", "Welcome to Spring MVC on Tomcat!");
return "home";
}
}

Application.java

java
package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.boot.builder.SpringApplicationBuilder;

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

home.jsp

jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Spring MVC on Tomcat</title>
</head>
<body>
<h1>${message}</h1>
<p>Your Spring application is successfully deployed to Tomcat!</p>
</body>
</html>

Deployment Steps

  1. Build the WAR file:

    bash
    mvn clean package
  2. Copy to Tomcat:

    bash
    cp target/spring-tomcat-demo-1.0.0.war $TOMCAT_HOME/webapps/myapp.war
  3. Start Tomcat:

    bash
    $TOMCAT_HOME/bin/startup.sh
  4. Access the application: Open your browser and navigate to http://localhost:8080/myapp/

Performance Tuning

To optimize your Spring application performance on Tomcat:

  1. Configure JVM Settings: Modify $TOMCAT_HOME/bin/catalina.sh to add JVM options:

    bash
    JAVA_OPTS="$JAVA_OPTS -Xms512m -Xmx1024m -XX:+UseG1GC"
  2. Enable Compression: In $TOMCAT_HOME/conf/server.xml:

    xml
    <Connector port="8080" protocol="HTTP/1.1"
    compression="on"
    compressionMinSize="2048"
    noCompressionUserAgents="gozilla, traviata"
    compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json" />
  3. Configure Connection Pool: In your Spring configuration:

    java
    @Bean
    public DataSource dataSource() {
    HikariConfig config = new HikariConfig();
    config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
    config.setUsername("user");
    config.setPassword("password");
    config.setMaximumPoolSize(10);
    return new HikariDataSource(config);
    }

Production Best Practices

  1. Use HTTPS: Configure Tomcat to use SSL/TLS
  2. Remove manager apps: Delete the manager and examples applications
  3. Set security headers: Configure security-related HTTP headers
  4. Implement proper logging: Configure log rotation
  5. Set up monitoring: Use tools like Spring Boot Actuator, Prometheus, or New Relic
  6. Use a load balancer: Deploy multiple Tomcat instances behind a load balancer

Summary

In this guide, we've covered how to deploy Spring applications to Apache Tomcat:

  1. Configuring your Spring project for WAR deployment
  2. Building a WAR file using Maven or Gradle
  3. Different methods for deploying to Tomcat (manual, Tomcat Manager, Maven plugin)
  4. Common configurations and customizations
  5. Troubleshooting common issues
  6. A complete real-world example
  7. Performance tuning and production best practices

Spring applications work seamlessly with Tomcat, making it an excellent choice for hosting your applications in production environments. By following the steps in this guide, you can ensure your Spring applications are properly configured, packaged, and deployed to Tomcat.

Additional Resources

Practice Exercises

  1. Create a simple Spring MVC application and deploy it to Tomcat using the steps in this guide.
  2. Modify the application to use a database connection through JNDI.
  3. Configure your application to use a different context path without renaming the WAR file.
  4. Implement a Spring Security configuration and test it in the Tomcat environment.
  5. Set up a development environment with hot reloading in Tomcat for faster development cycles.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)