How to Build Spring 5 REST API with Embedded Tomcat without using Spring Boot



In the previous article, we have added logging support using the Logback logging framework. Now, we are going to add embedded tomcat to the Spring REST application without using Spring Boot.

Let’s Get Started

Add Tomcat Dependencies and Shade Plugin

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/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javachinna</groupId>
	<artifactId>spring-rest-jwt-demo</artifactId>
	<packaging>jar</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-rest-jwt-demo Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<properties>
		<java-version>11</java-version>
		<spring.version>5.2.3.RELEASE</spring.version>
		<hibernate.version>5.4.1.Final</hibernate.version>
		<tomcat.version>9.0.37</tomcat.version>
		<slf4j.version>1.7.25</slf4j.version>
	</properties>
	<dependencies>
		<!-- Spring Web MVC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<!-- Required for converting JSON data to Java object and vice versa -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.9.10.5</version>
		</dependency>
		<!-- Servlet API -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>4.0.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.2.3</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jul-to-slf4j</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>log4j-over-slf4j</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.9.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>2.2.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.16</version>
			<scope>runtime</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-core</artifactId>
			<version>${tomcat.version}</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<version>${tomcat.version}</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.threeten/threetenbp -->
		<dependency>
			<groupId>org.threeten</groupId>
			<artifactId>threetenbp</artifactId>
			<version>1.4.2</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>SpringRestJwt</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>${java-version}</source>
					<target>${java-version}</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-shade-plugin</artifactId>
				<version>3.2.4</version>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>shade</goal>
						</goals>
						<configuration>
							<transformers>
								<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
									<mainClass>com.javachinna.embedded.TomcatLauncher</mainClass>
								</transformer>
								<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
									<resource>META-INF/spring.handlers</resource>
								</transformer>
								<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
									<resource>META-INF/spring.schemas</resource>
								</transformer>
								<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
									<resource>META-INF/spring.factories</resource>
								</transformer>
							</transformers>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

List of Changes

  • Changed the packaging type to jar
  • Upgraded Servlet API version from 3.0.1 to 4.0.1 to make it compatible with Tomcat 9.0 version
  • Added embedded tomcat core and Jasper (JSP engine) dependencies
  • Upgraded spring-data-jpa to 2.2.6.RELEASE version
  • Added threetenbp dependency which is required for spring-data-jpa
  • Added maven-shade-plugin to build a fat jar and configured transformers
    • ManifestResourceTransformer used for configuring our Main class TomcatLauncher
    • Each Spring jar has configuration files like spring.handlers, spring.schemas, and spring.factories in the META-INF directory. The default behavior of the shade plugin is to overwrite those files. To avoid this, AppendingTransformer is being used for appending the contents into a single file.

Create Main Class

TomcatLauncher.java

This class is responsible for adding our application to the embedded tomcat server and starting it on port 8080

package com.javachinna.embedded;

import java.io.File;

import org.apache.catalina.startup.Tomcat;

public class TomcatLauncher {
	public static void main(String[] args) throws Exception {
		Tomcat tomcat = new Tomcat();
		tomcat.setPort(8080);
		tomcat.addWebapp("", new File("src/main/").getAbsolutePath());
		tomcat.getConnector();
		tomcat.start();
		tomcat.getServer().await();
	}
}

Build Application

You can build a fat jar by executing mvn package command in your source directory

Run Application

You can run the application by running java -jar target\SpringRestJwt.jar command in your source directory

Source code

https://github.com/JavaChinna/spring-rest-embedded-tomcat

Conclusion

That’s all folks. In this article, we have embedded tomcat into our Spring REST application.

Please share this article with your friends if you like it. Thank you for reading.

Leave a Reply