Cómo configurar el Tomcat embebido de Spring Boot

0
23461

Una forma sencilla de poder configurar nuestro Tomcat embebido en Spring Boot y aprovecharlo todo lo posible.

Índice de contenidos

1. Introducción

Spring Boot nos permite «olvidarnos» de ciertas cuestiones de configuración que con Spring pueden ser algo tediosas o que simplemente queremos aprovechar todo el potencial de las anotaciones, ya que nos quita el tener que estar trabajando con archivos XML de configuración, aunque esto no quita el hecho de que podamos seguir usándolo de la manera antigua.

Todo esto surge con mi necesidad de levantar un contexto de una versión muy antigua de Spring en un Spring Boot actual, y ya de paso aprovechar el Tomcat embebido y no tenerlo por separado.

Como ejemplo intentaremos configurar un contexto tal como podríamos hacer en el «server.xml» de un Tomcat cualquiera, pero lo haremos completamente en Java.

Nuestro reto será configurar una variable de entorno que será un path que use un bean ajeno y un recurso que será la configuración de nuestro data source.

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: portátil MacBook Pro 15′ (2 Ghz Intel Core I7, 8GB DDR3).
  • Sistema operativo: Mac OS Sierra 10.12.5
  • Entorno de desarrollo: Eclipse Neon 3
  • Spring Boot 1.5.4 (Tomcat 8.5 embebido)

3. Creando nuestra clase para la configuración

En primer lugar crearemos una clase que nos servirá de configuración y se llamará AppConfiguration.java. El nombre puede ser el que queramos, ya que no afecta a Spring Boot en ningún sentido, podría llamarse TomcatConfiguration o como se desee. En ella configuraremos el data source y Tomcat.

Nuestra clase de configuración quedaría tal que:

@Configuration
@EnableTransactionManagement
public class AppConfiguration {
}

La anotación «@Configuration» es la que le permite a Spring Boot entender que esta clase aporta configuración que puede ser distinta a la que él autoconfigura en un principio.

La anotación «@EnableTransactionManagement» es relevante con respecto al data source.

4. Configurando nuestro contexto de ejemplo

Una vez tenemos creado un punto de partida procederemos a configurar el data source y Tomcat creando un par de beans, uno de ellos será el data source y el otro nos permitirá crear la configuración del Tomcat embebido.

Debe tenerse muy en cuenta que, dependiendo de las características del proyecto y de cómo debe configurarse Tomcat según su versión, el siguiente código puede variar bastante del ejemplo a vuestro proyecto, ya que al fin y al cabo es configuración y hay un amplio abanico de posibilidades y casos.

Nuestra clase de configuración tomaría la siguiente forma:

@Configuration
@EnableTransactionManagement
public class AppConfig {
    // La anotación Primary hace que este bean tenga prioridad sobre otros iguales, no es
    // necesario. Además, el data source es muy peculiar y no condiciona nuestra configuración
    // de Tomcat.
	@Primary
	@Bean
	public DataSource dataSource() {
        // Configuración de JNDI que necesita un bean del proyecto ya que requiere unos
        // argumentos.
		final JndiObjectFactoryBean bean = new JndiObjectFactoryBean();

		final Properties jndiEnvironment = new Properties();
		jndiEnvironment.setProperty("name", "java:comp/env/customDirExample");
		bean.setJndiEnvironment(jndiEnvironment);

		bean.setJndiName("java:comp/env/jdbc/exampleDB");
		bean.setProxyInterface(DataSource.class);
        // Como comentaba anteriormente, el caso del lookup fue necesario por peculiaridades del
        // proyecto.
		bean.setLookupOnStartup(false);
		bean.afterPropertiesSet();

        // Devuelve el data source con los cambios necesarios.
		return (DataSource) bean.getObject();
	}

    // Este bean nos permite configurar Tomcat, dependiendo de las necesidades puede variar
    // bastante la implementación, por lo cual recomiendo encarecidamente revisar la documentación
    // de Spring Boot e ir incrementalmente añadiendo configuración, según sea necesario.
	@Bean
	public TomcatEmbeddedServletContainerFactory tomcatFactory() {
		return new TomcatEmbeddedServletContainerFactory() {

			@Override
			protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
				tomcat.enableNaming();
				return super.getTomcatEmbeddedServletContainer(tomcat);
			}

			@Override
			protected void postProcessContext(Context context) {
                // Nos permite cambiar el contexto una vez levantado automáticamente por Spring
                // Boot.

                // Creamos la variable que empleará uno de los beans del proyecto.
				ContextEnvironment environment = new ContextEnvironment();
				environment.setName("customDir");
				environment.setType("java.lang.String");
				environment.setValue("/Users/username/...");
                                
                // Configuramos el data source.
				ContextResource resource = new ContextResource();
				resource.setName("jdbc/exampleDB");
				resource.setAuth("Container");
				resource.setType("javax.sql.DataSource");
				resource.setProperty("maxTotal", "100");
				resource.setProperty("maxIdle", "30");
				resource.setProperty("maxWaitMillis", "1000");
				resource.setProperty("driverClassName", "com.mysql.jdbc.Driver");
				resource.setProperty("username", "root");
				resource.setProperty("password", "root");
				resource.setProperty("url", "jdbc:mysql://localhost:3306/exampledb?autoReconnect=true&useSSL=false");
				resource.setProperty("factory", "org.apache.tomcat.jdbc.pool.DataSourceFactory");

                // Una vez creada la variable de entorno y el recurso del data source los añadimos
                // al contexto.
				context.getNamingResources().addEnvironment(environment);
				context.getNamingResources().addResource(resource);

			}
		};
	}

}

Como puede verse, la implementación está plagada de peculiaridades que no tienen por qué ser así en todos los proyectos, pero ya que nos basamos en un caso real es necesario tenerlo en cuenta.

Lo que realmente configura Tomcat son unas pocas líneas y realmente simples; es como la etiqueta «Context» de un server.xml pero en código Java.

Dependiendo de nuestras necesidades podemos sobreescribir el método que más nos convenga. En este ejemplo sobreescribimos el método postProcessContext, pero hay otros para configurar el contexto como configureContext. También podemos cambiar el baseDir entre otras cosas, aunque la mayor parte depende de sus los componentes del contexto como ContextEnvironment o ContextResource.

5. Una pequeña mejora

Una vez que tenemos bien configurado nuestro Tomcat hay algo que podemos mejorar. En lugar de escribir directamente la configuración del datasource y otros parámetros, ¿por qué no llevárnoslo todo a un YML?, ¡aprovechemos que Spring Boot puede tomar configuración de un YML!.

Para tomar la configuración de un YML necesitamos primero crear una carpeta en la raíz del proyecto y la llamaremos «config», dentro de esta crearemos el archivo «application.yml» con la siguiente configuración:

server:
  port: 8008
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/exampledb?autoReconnect=true&useSSL=false
    name: exampledb
    username: root
    password: root
    type: javax.sql.DataSource
    driver-class-name: com.mysql.jdbc.Driver
    validation-query: SELECT 1 FROM ExampleTable

Mediante el YML le estamos diciendo a Spring Boot que queremos que su Tomcat use el puerto 8008 con la configuración del datasource que le estamos poniendo.

Todas las propiedades que podemos decirle a Spring Boot que configure las podemos encontrar aquí.

Pero Spring Boot aún no sabe nada de nuestro archivo de configuración, para que lo reconozca y lo use hay que ir a nuestro Eclipse y añadírselo en el classpath. Para esto configuramos el classpath de «Ejecutar como» o «Run as» -> «Run configurations». En el perfil que empleamos para ejecutar nuestra aplicación vamos a la pestaña classpath, hacemos click sobre «User Entries» o «Entradas de Usuario» y le damos al botón «Avanzado», seleccionamos añadir una carpeta y le decimos que añada nuestra carpeta config.

Una vez añadida la carpeta config al classpath no debería haber ningún problema, pero tenemos que acceder a estos valores desde el código con la anotación @Value, añadiendo la siguiente pieza de código al principio de nuestra clase de configuración:

@Value("${spring.datasource.driver-class-name}")
private String DB_DRIVER;

@Value("${spring.datasource.password}")
private String DB_PASSWORD;

@Value("${spring.datasource.url}")
private String DB_URL;

@Value("${spring.datasource.username}")
private String DB_USERNAME;

Una vez conseguidos los valores que necesitemos procedemos a reemplazar las string que antes metíamos directamente por nuestros parámetros obtenidos del YML. Ahora mejor, ¿verdad?

6. Conclusiones

Como hemos visto, configurar nuestro Tomcat embebido es realmente sencillo, el verdadero reto es ir configurando poco a poco nuestro Spring Boot y Tomcat para satisfacer las necesidades de nuestro proyecto. Para ello recomiendo paciencia, tener cerca la documentación de Spring Boot y un motor de búsqueda.

Configurar el Tomcat embebido nos permite incluir la configuración general de nuestra aplicación y dejar en archivos externos sólo lo que queramos parametrizar simplificando, en algunos casos, enormemente la instalación de nuestra aplicación Spring Boot en cualquier sistema.

7. Referencias

  • Spring Boot Docs. Documentación de Spring Boot.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad