C2B2 logo icon

How to Create Microservices with Tomcat

Creating microservices depends on creating lightweight, self-contained services that can be managed as an atomic unit. So how do we create a Tomcat based microservice without the complexity of using a full installation of Tomcat? Enter Tomcat Embedded.

Traditionally, web applications are packaged as a WAR file and deployed to server containers such as Tomcat, JBoss, Oracle WebLogic or Payara. Instead of deploying the application in a server, the server can be embedded inside your application, resulting in a standalone application packaged as a JAR file that can be executed from the command line. 

In this example, I will create a simple HTTP servlet that uses annotations, and acts as the end point for calling the service - and implements the business logic for the service and Tomcat as an embedded server.   Maven has a Tomcat plugin that allows you to compile and package the dependencies needed to run the web application with Tomcat embedded.

Create and configure a Maven Project 

Create a new blank Maven project in your favourite IDE - for this example, I used JBoss Developer Studio, which is based on Eclipse. Then configure the dependencies required to run Tomcat in an embedded mode, and the plugins to compile and package the project in a single uber-JAR. 

Add the following dependencies in the <dependencies> tag to the pom.xml file

<modelVersion>4.0.0</modelVersion>
<groupId>uk.co.c2b2.blogs.microservices</groupId>
<artifactId>tomcat-microservice-app</artifactId>
<version>1.0</version>
<packaging>war</packaging>
<name>demo-tomcat-microservice</name>
<url>http://maven.apache.org</url>
<properties>
	<tomcat.version>8.0.28</tomcat.version>
</properties>
<dependencies>
	<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-core</artifactId>
		<version>${tomcat.version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-logging-juli</artifactId>
		<version>${tomcat.version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-jasper</artifactId>
		<version>${tomcat.version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat</groupId>
		<artifactId>tomcat-jasper</artifactId>
		<version>${tomcat.version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat</groupId>
		<artifactId>tomcat-jasper-el</artifactId>
		<version>${tomcat.version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat</groupId>
		<artifactId>tomcat-jsp-api</artifactId>
		<version>${tomcat.version}</version>
	</dependency>
</dependencies>

The following build plugins need to be added to the pom.xml to compile and package the necessary dependencies to a runnable JAR file.

  • maven-compiler-plugin
    Used to compile the Java source code
     
  • maven-assembly-plugin
    Used to aggregate the project output along with its dependencies, modules, documentation, and other files into a single distributable archive.

Build plugins are executed during the build and should be configured in the <build/> element in the POM.  Add the following code to the pom.xml file:

<build>
    <finalName>tomcat-microservices-app</finalName>
    <resources>
        <resource>
      <directory>src/main/webapp</directory>
		<targetPath>META-INF/resources</targetPath>
	  </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-compiler-plugin</artifactId>
		<version>2.3.2</version>
		<inherited>true</inherited>
		<configuration>
		    <source>1.8</source>
		    <target>1.8</target>
		</configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
	     <artifactId>maven-assembly-plugin</artifactId>
	     <configuration>
	         <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
		   </descriptorRefs>
		   <finalName>tomcat-microservices-app-${project.version}</finalName>
		   <archive>
                    <manifest>
                      <mainClass>co.uk.c2b2.blogs.microservices.Main</mainClass>
			 </manifest>
		   </archive>
            </configuration>
	     <executions>
	        <execution>
		     <phase>package</phase>
                       <goals>
                           <goal>single</goal>
			   </goals>
		  </execution>
            </executions>
        </plugin>	
    </plugins>
</build>


Create the class used to launch the Tomcat Embedded application

Create the Main class in the uk.co.c2b2.blogs.microservices that will be used to launch the instance of the Tomcat Embedded server.  This class will have a main method that will be used to setup the embedded Tomcat.

package co.uk.c2b2.blogs.microservices;

import java.io.File;
import java.util.Optional;

import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.core.StandardContext;

public class Main {
	public static final Optional<String> port = Optional.ofNullable(System.getenv("PORT"));

	public static void main(String[] args) throws Exception {

		String webappDirLocation = "src/main/webapp/";
		Tomcat tomcat = new Tomcat();
		
		int httpPort = Integer.parseInt(System.getProperty("tomcat.http.port", "8080"));
		tomcat.setPort(httpPort);

		StandardContext ctx = (StandardContext) tomcat.addWebapp("/", new File(webappDirLocation).getAbsolutePath());

		File additionWebInfClasses = new File("target/classes");
		WebResourceRoot resources = new StandardRoot(ctx);
		resources.addPreResources(
				new DirResourceSet(resources, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/"));
		ctx.setResources(resources);

		tomcat.start();
		tomcat.getServer().await();

	}
}

The name of this class needs to be configured in the maven-assembly-plugin in the <mainClass> tag in the POM file.

<configuration>
	. . . .
<archive>
       	<manifest>
              	<mainClass>co.uk.c2b2.blogs.microservices.Main</mainClass>
		</manifest>
	</archive>
</configuration>


Create the HTTP Servlet Endpoint

The Microservice entry point is made via a call to an HTTP Servlet.  Create the servlet named MicroservicesServlet in the package uk.co.c2b2.blogs.microservices.servlet and add the following code.

package co.uk.c2b2.blogs.microservices.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "MicroservicesServlet", urlPatterns = { "/microservices" })
public class MicroservicesServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public MicroservicesServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		ServletOutputStream out = response.getOutputStream();
		out.write("<html><h2>Hello from C2B2 Tomcat Microservices Blog</h2></html>".getBytes());
		out.flush();
		out.close();
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}
}

The @WebServlet annotation declares the servlet instead of using XML web deployment descriptor (web.xml). The annotations are processed by the container at deployment time. The doGet method for the servlet prints out a welcome message.

Running the Tomcat Microservice

To compile and package the application running the following Maven commands either through the Java IDE or on a Command Line Window or terminal:

  • Compile the project - mvn clean compile
  • Package the application - mvn package

A runnable JAR file is created named ‘tomcat-microservices-app-0.0.1-SNAPSHOT-jar-with-dependencies.jar’ and written to the project’s target folder. The jar file contains the web application WAR file together with all the dependant libraries to run the application as a Tomcat Embedded server.

To run the application, open a Command Line Window or terminal and change directory to the Maven projects target folder and execute the following command:

java -jar -Dtomcat.http.port=8181 tomcat-microservices-app-1.0-jar-with-dependencies.jar

To test the web application open a browser and enter the URL:  http://localhost:8181/microservices to display the following HTML page:

Conclusion

This is a very simple application that demonstrates how to create a web based Microservice running an Tomcat Embedded server by compiling and packaging a runnable JAR file with the Tomcat Embedded libraries. In a real world scenario, the endpoint to the microservice could be exposed using REST, CXF or JAX RS Webservices and would implement the business logic to be executed by the microservice.