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:
- Embedded Tomcat (common in Spring Boot applications)
- 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
:
<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
:
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:
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:
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:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
In Gradle:
dependencies {
// ... other dependencies
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}
Building Your WAR File
Using Maven
Run the following command:
mvn clean package
This will create a WAR file in the target
directory.
Using Gradle
Run the following command:
./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
- Copy your WAR file to the
webapps
directory in your Tomcat installation. - Start Tomcat (if it's not already running) using the
startup.sh
(Linux/Mac) orstartup.bat
(Windows) script in thebin
directory. - Tomcat will automatically unpack and deploy your application.
Example:
# 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
- Configure the Tomcat Manager by adding a user in
$TOMCAT_HOME/conf/tomcat-users.xml
:
<tomcat-users>
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<user username="admin" password="password" roles="manager-gui,manager-script"/>
</tomcat-users>
- Access Tomcat Manager at
http://localhost:8080/manager/html
- 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
:
<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
:
<servers>
<server>
<id>tomcat-server</id>
<username>admin</username>
<password>password</password>
</server>
</servers>
Deploy with Maven:
mvn tomcat7:deploy
Or redeploy if the application already exists:
mvn tomcat7:redeploy
Common Deployment Configurations
Context Path Configuration
You can specify the context path (URL base path) for your application in several ways:
-
WAR filename: The WAR file name becomes the context path by default. For example,
myapp.war
will be accessible athttp://localhost:8080/myapp
-
Using a context.xml file: Create a
META-INF/context.xml
file in your WAR:
<?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
:
<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:
@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:
- Check catalina.out log file
- Remove your application's WAR from the webapps directory
- Start Tomcat
- Fix the identified issues
- 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
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
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
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
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
<%@ 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
-
Build the WAR file:
bashmvn clean package
-
Copy to Tomcat:
bashcp target/spring-tomcat-demo-1.0.0.war $TOMCAT_HOME/webapps/myapp.war
-
Start Tomcat:
bash$TOMCAT_HOME/bin/startup.sh
-
Access the application: Open your browser and navigate to
http://localhost:8080/myapp/
Performance Tuning
To optimize your Spring application performance on Tomcat:
-
Configure JVM Settings: Modify
$TOMCAT_HOME/bin/catalina.sh
to add JVM options:bashJAVA_OPTS="$JAVA_OPTS -Xms512m -Xmx1024m -XX:+UseG1GC"
-
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" /> -
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
- Use HTTPS: Configure Tomcat to use SSL/TLS
- Remove manager apps: Delete the manager and examples applications
- Set security headers: Configure security-related HTTP headers
- Implement proper logging: Configure log rotation
- Set up monitoring: Use tools like Spring Boot Actuator, Prometheus, or New Relic
- 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:
- Configuring your Spring project for WAR deployment
- Building a WAR file using Maven or Gradle
- Different methods for deploying to Tomcat (manual, Tomcat Manager, Maven plugin)
- Common configurations and customizations
- Troubleshooting common issues
- A complete real-world example
- 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
- Official Apache Tomcat Documentation
- Spring Framework Documentation
- Spring Boot Documentation on Traditional Deployment
Practice Exercises
- Create a simple Spring MVC application and deploy it to Tomcat using the steps in this guide.
- Modify the application to use a database connection through JNDI.
- Configure your application to use a different context path without renaming the WAR file.
- Implement a Spring Security configuration and test it in the Tomcat environment.
- 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! :)