Configuración de entornos flexible en Spring utilizando SpEL

Introducción

En general cuando desarrollas una aplicación de cualquier tipo te enfrentas al reto de:

1) Configurar la aplicación de una manera sencilla

La configuración tiene que ser cómoda de modificar y tiene que estar centralizada (evitando que este desperdigada en multitud de ficheros de configuración las rutas, parámetros de conexión etc…)

2) Que un mismo ejecutable (jar o war en el caso de java) sirva para diferentes entornos.

Evitar tener que hacer un build para diferentes entornos (Además probablemente en un entorno corporativo no tengas acceso a las contraseñas y a las rutas de los recursos, etc.. de producción) A esto es a lo que me refiero con externalizable.

Spring es una poderosa y elegante herramienta que permite configurar una aplicación y establecer las dependencias entre sus clases a través de anotaciones o mediante archivos xml.

Pero esta potencia también puede llevar al peligro de que si no somos cuidadosos tengamos los parámetros de conexión, contraseñas, URL y rutas desperdigadas en varios archivos.

Para esto Spring ofrece herramientas que permiten cargar propiedades y valores de archivos ‘.properties‘ y además estos archivos pueden encontrase fuera del jar o del war e incluso pueden estar cifrados. Con esto se soluciona la centralización y la externalización.

El problema

Hecha la introducción paso a explicar el problema: Había que configurar una aplicación web en Spring en diferentes entornos en una misma máquina (un entorno en un Jetty y otro en un Tomcat), por lo que había que externalizar la configuración y además al estar en la misma máquina no servía que la ruta al fichero de configuración fuera fija (de estilo ‘/home/usuario/aplicacion.properties‘)

La solución

Ha sido utilizar el bean ‘PropertyPlaceholderConfigurer‘ de Spring y utilizar SpEL (Spring Expression Language) de esta forma:

01
<?xml version="1.0" encoding="UTF-8"?>
02
<beans xmlns="http://www.springframework.org/schema/beans"
03
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
05
 >
06
...
07
 <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
08
  <property name="locations" value="#{systemProperties['aplicacion.config'] != null ? 'file:' + systemProperties['aplicacion.config'] :'classpath:'}application.properties"/>
09
 </bean>
10
 ...
11
 </beans>

Código 01. Configuración xml de ‘propertyConfigurer’

La clave está en la línea 8. Si está definida la propiedad del sistema ‘aplicacion.config‘ buscará en el sistema de ficheros, el archivo de configuración ‘aplicacion.properties‘ en la dirección que indica su valor. Si no, busca el ‘aplication.properties‘ en el classpath (es decir dentro del war), por lo que este sería el archivo de configuración de la aplicación por defecto.

Un ejemplo del contenido de ‘aplicacion.properties‘ podría ser

1
...
2
aplicacion.config.pathfiles=/home/miguel/aplicacion/tmp
3
...

Código 02. Ejemplo de contenido de aplicacion.properties

Y la manera de usarlo dentro de la configuración xml de Spring sería:

01
<?xml version="1.0" encoding="UTF-8"?>
02
<beans xmlns="http://www.springframework.org/schema/beans"
03
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
05
 >
06
...
07
 <bean id="utilFichero" class="com.logicaalternativa.ejemplo.UtilFicheroImp"> 
08
  <property name="directorio" value="${aplicacion.config.pathfiles}"/>
09
 </bean>
10
 ...
11
 </beans>

Código 03. Ejemplo de como se utilizan los valores definidos en el archivo de configuración

Ya sólo me queda indicar como se define esa propiedad. En el Tomcat un buen sitio es el ‘catalina.properties de su directorio ‘config‘. Se definiría así:

1
...
2
aplicacion.config=/home/miguel/config-aplicacion-tomcat/
3
...

Código 04. Configurando el Tomcat

O directamente definiendo la propiedad al arrancar la máquina virtual. Por ejemplo si tu proyecto tiene configurado el plugin,  arrancando el jetty embebido de mvn de la siguiente manera:

1
mvn -Daplicacion.config=/home/miguel/config-aplicacion-jetty/ jetty:run

Código 05. Ejemplo al arrancar el jetty de mvn

En los ejemplos en los dos directorios ‘/home/miguel/config−aplicacion−jetty/‘ y ‘/home/miguel/config−aplicacion−tomcat/‘ se encontrarían sendos archivos ‘aplicacion.properties‘ cada uno configurados con los valores para cada entorno.

Espero que os sirva.

M.E.