Aplicación web Java autocontenida con Tomcat Embedded

Escrito por el , actualizado el .
java planeta-codigo programacion
Enlace permanente Comentarios

Java

La tendencia de las aplicaciones es que sean construidas como múltiples servicios pequeños que colaboran entre si en vez de consistir en una aplicación grande desplegada en un servidor de aplicaciones. La aparición de nuevas tecnologías como Docker facilitan la construcción y despliegue de los microservicios. Los microservicios con su máxima de bajo acoplamiento y alta cohesión tratan de incluir todo lo necesario para funcionar evitando las dependencias de cualquier tipo de elemento fuera de su ámbito no incluyendo el uso de otros servicios. Con Docker es posible desplegarlos en cualquier máquina que disponga del servicio, esto evita problemas de configuración al pasar la aplicación de un entorno de desarrollo a uno de producción ya que las características del entorno de desarrollo y el de producción pueden ser idénticos.

Los microservicios pueden ser autocontenidos de tal forma que incluyen todo lo necesario para prestar su servicio evitando por ejemplo sin depender de un servidor de aplicaciones en el que desplegar la aplicación que ha de ser instalado previamente, para ello pueden incluir un servidor embebido de Tomcat, de Jetty o usando Spring Boot. Esto evita malos funcionamiento por diferencias en la configuración o de versiones de los servidores en cada uno de los entornos, además hace más fácil el despliegue en una nueva máquina siendo lo único necesario el microservicio, sin necesidad de disponer previamente un servidor externo. Por otra parte si usamos Docker para el microservicio evitamos que configurar la máquina física o virtual directamente, todo lo que necesite el microservicio estará en la imagen Docker, nuevamente evitamos problemas de configuración entre entornos.

Para hacer cualquier aplicación autocontenida sin necesidad de instalar el servidor de aplicaciones como entorno en el que desplegar la aplicación podemos usar Tomcat Embedded o mejor y con el mismo efecto usar Spring Boot con la posibilidad de usar Tomcat, Jetty o Undertow, realmente Spring Boot usa las versiones embebibles del servidor que se use y además se encarga de inicializar el contenedor IoC de Spring. En este caso usando Tomcat Embedded directamente disponiendo del archivo .war típico de una aplicación web en Java podemos desplegarlo en el servidor embebido, el inicio de la aplicación será como cualquier otra aplicación Java, con su método public static void main(String[] args), usando la API ofrecida por Tomcat podemos iniciar el servidor de forma programática y realizar el despliegue de la aplicación .war.

Para la demostración usaré la aplicación con los ejemplos que hice para el libro PulgIn Tapestry que trataba del el framework de desarrollo Apache Tapestry. Primeramente deberemos añadir al proyecto la dependencia de tomcat-embedded de forma que podamos importar las clases y paquetes de Tomcat a usar en la clase que iniciará la aplicación.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
description = 'TomcatEmbedded'
version = '0.1'

apply plugin: 'application'
apply plugin: 'eclipse'
apply plugin: 'java'

mainClassName = 'io.github.picodotdev.blogbitix.tomcatEmbedded.Main'

repositories {
    mavenCentral()
}

dependencies {
	compile('org.apache.tomcat.embed:tomcat-embed-core:8.0.20')
	compile('org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.0.20')
	compile('org.apache.tomcat.embed:tomcat-embed-jasper:8.0.20')
	compile('junit:junit:4.12')
}

jar {
    manifest {
        attributes('Main-Class': 'io.github.picodotdev.blogbitix.tomcatEmbedded.Main')
    }
}

task wrapper(type: Wrapper) {
	gradleVersion = '2.3'
}

applicationDistribution.from('tomcat/webapps/PlugInTapestry.war') {
    into "tomcat/webapps/"
}
build.gradle

Posteriormente crearemos una clase Java con su método main que inicie el servidor de aplicaciones embebido con la aplicación web desplegada en él, podemos indicar el puerto que queremos que escuche y las configuraciones que necesitemos tal como si lo configurásemos el archivo server.xml o context.xml pero usando código Java, usaremos la API ofrecida por las clases incluidas en las dependencias anteriores (org.apache.catalina.startup.Tomcat).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package io.github.picodotdev.blogbitix.tomcatEmbedded;

import org.apache.catalina.startup.Tomcat;

public class Main {

	public static void main(String[] args) throws Exception {
		Tomcat tomcat = new Tomcat();
		tomcat.setBaseDir("tomcat");
		tomcat.setPort(8080);
		
		// Para configurar el puerto seguro
		// http://www.copperykeenclaws.com/adding-an-https-connector-to-embedded-tomcat-7/
		// Connector httpsConnector = new Connector();
		// httpsConnector.setPort(443);
		// httpsConnector.setSecure(true);
		// httpsConnector.setScheme("https");
		// httpsConnector.setAttribute("keyAlias", keyAlias);
		// httpsConnector.setAttribute("keystorePass", password);
		// httpsConnector.setAttribute("keystoreFile", keystorePath);
		// httpsConnector.setAttribute("clientAuth", "false");
		// httpsConnector.setAttribute("sslProtocol", "TLS");
		// httpsConnector.setAttribute("SSLEnabled", true);
		//
		// Tomcat tomcat = new Tomcat();
		// Service service = tomcat.getService();
		// service.addConnector(httpsConnector);
		//
		// Connector defaultConnector = tomcat.getConnector();
		// defaultConnector.setRedirectPort(443);

		tomcat.addWebapp("/PlugInTapestry", "tomcat/webapps/PlugInTapestry.war");
		tomcat.start();
		
		// Puerto para enviar el comando SHUTDOWN
		// telnet localhost 8005
		// SHUTDOWN
		tomcat.getServer().setPort(8005);
		tomcat.getServer().await();
	}
}
Main.java

Generamos el war de la aplicación que queremos desplegar embebida, e iniciamos la aplicación con la clase que contiene el método main con Gradle o desde la linea de comandos con java, necesitaremos descargar las librerías de Tomcat Embedded y en este ejemplo copiarlas al directorio lib/ junto con la librería TomcatEmbedded-0.1.jar que contiene la clase Main construida con el comando gradlew build:

1
2
3
4
5
$ ./gradlew build

$ ./gradlew run
$ java -classpath "lib/*" io.github.picodotdev.blogbitix.tomcatEmbedded.Main
$ ./TomcatEmbedded
startup.sh

Iniciando TomcatEmbedded TomcatEmbedded iniciado

Aplicación web en TomcatEmbedded

La tendencia actual es que las aplicaciones evolucionen hacia microservicios por varias características deseables que ofrecen como al ser más pequeñas las funcionalidades sean más manejables, sean reemplazables, posibilidad de usar la tecnología más adecuada según el servicio desde lenguaje de programación al sistema de persistencia (relacional o noSQL), facilidad de despliegue, …. Si te interesan los microservicios un libro muy interesante y recomendable es Building Microservices. Proporciona una visión detallada de los diferentes aspectos que deben tratar las aplicaciones construidas según esta arquitectura.

El código fuente completo del ejemplo y el código fuente de la aplicación web usada los puedes encontrar en mi repositorio de GitHub. Finalmente he de decir que la aplicación usada aunque es un ejemplo no es simple (usa Tapestry, Spring, Hibernate, Shiro, H2) y a pesar de ello no he tenido ninguna excepción extraña que haya tenido que resolver, con esto quiero decir que usar Tomcat Embedded me ha resultado totalmente fiable.


Comparte el artículo: