Perfiles en Maven

Última actualización: 26/10/2022
maven

Durante el desarrollo de aplicaciones que van a ser utilizadas en distintos entornos (testing, producción, etc.) solemos encontrarnos con el problema de adaptarlas a cada uno de ellos. Por ejemplo, los parámetros utilizados para la conexión a la base de datos. También es posible que necesitemos incluir librerías distintas en función de la versión de Java o incluso el sistema operativo. La casuística puede ser variada.

Apache Maven nos ayuda a solucionar esta problemática con elegancia y practicidad mediante el uso de perfiles. Un perfil es una configuración de Maven (dependencias, variables, plugins…) que solo queremos aplicar \ activar en determinadas circunstancias, ya sea especificando el perfil o bien de forma automática siempre que se cumpla cierta condición.

En este pequeño tutorial exploraremos el uso básico de los perfiles de Maven. Como punto de partida, resolveremos un escenario muy común.

  1. El problema a resolver
  2. Soluciones
    1. Definir las variables en el pom
    2. Un fichero para cada entorno
  3. Perfiles en los IDE
  4. Activación automática de perfiles
    1. En el fichero settings.xml
    2. Según una variable de entorno
    3. Chequear la existencia de un fichero
    4. De forma predeterminada
    5. Según el sistema operativo
    6. Según la versión de Java que use Maven
  5. Código de ejemplo

El problema a resolver

Imaginemos un proyecto Maven consistente en una aplicación web en el que utilizamos dos ficheros de configuración: el del sistema de logs log4j y otro denominado db.properties con la cadena de conexión y las credenciales de la base de datos.

Es habitual que un proyecto de este tipo deba ser desplegado en al menos tres entornos de explotación diferentes: el equipo de cada desarrollador, un servidor de pruebas y el de producción final. Para simplificar el tutorial, vamos a considerar un entorno de desarrollo y otro de pruebas. El objetivo es utilizar una base de datos y un nivel de log distinto en cada uno de ellos.

Mostraré dos formas de afrontar esta casuística para que puedas elegir la solución que más te convenga.

Soluciones

Definir las variables en el pom

Con esta estrategia, establecemos en el pom.xml para cada perfil el valor que queremos asignar a cada variable de configuración. De este modo, centralizamos en un único fichero los parámetros que dependen del entorno / perfil.

Seguimos estos pasos:

1-. Crear la sección profiles con los dos perfiles. Dentro de cada uno se definen las variables y sus valores en un bloque properties:

<profiles>
    <profile>
        <id>desarrollo</id>
        <properties>
            <log.level>DEBUG</log.level>
            <db.url>jdbc:mysql://localhost:3306/profiles</db.url>
            <db.user>dev</db.user>
            <db.password>devpassword</db.password>
         </properties>
        </profile>
        <profile>
            <id>pruebas</id>
            <properties>
                <log.level>INFO</log.level>
                <db.url>jdbc:mysql://192.168.1.30:3306/profiles</db.url>
                <db.user>pro</db.user>
                <db.password>45fgU23</db.password>
            </properties>
        </profile>
</profiles>

¡Mucho cuidado! Hay que evitar versionar y\o distribuir datos sensibles tales como contraseñas. En el ejemplo estoy asumiendo que en el entorno de pruebas no hay nada especialmente delicado.

2-. Usamos estas variables en los ficheros donde queremos que sean reemplazadas.
/src/main/resources/log4j.xml:

<root>
   <priority value="${log.level}" />
   <appender-ref ref="console" />
   <appender-ref ref="file" />
</root>

/src/main/resources/db.properties

driver=com.mysql.jdbc.Driver
db.url = ${db.url}
db.user = ${db.user}
db.password = ${db.password}

En el caso del fichero de configuración de Spring Boot, este es el formato:

spring.datasource.username = @db.user@ 

3-. Activamos el filtrado de recursos para que Maven cambie las variables:

<build>
    <resources>
        <resource>
            <filtering>true</filtering>
            <directory>src/main/resources</directory>
        </resource>
    </resources>
</build>

4-. Al ejecutar una orden, debemos proporcionar los perfiles a usar, separados por comas, con el parámetro -P. Más adelante veremos en detalle la aplicación de perfiles.

mvn clean package -P desarrollo 
Un fichero para cada entorno

Otra alternativa consiste en tener un fichero de configuración distinto para cada entorno. Esto es, tendremos un par de ficheros db.properties y log4j.xml para el equipo del programador y otro par db.properties y log4j.xml para el entorno de pruebas.

Seguimos los siguientes pasos:

1-. Se organizan los ficheros de configuración en directorios según entornos/perfiles y fuera del /src/main/resources para evitar tener que hacer configuraciones adicionales de ensamblado. Siguiendo este criterio con nuestro ejemplo, tendríamos esta estructura.

2-. En el pom.xml definimos los perfiles tal y como hicimos en la sección anterior. Ahora tendrán una única variable con la carpeta en la que se encuentran los ficheros específicos para el perfil:

<profiles>
        <profile>
            <id>desarrollo</id>
            <properties>
                <profile.dir>src/main/profiles/desarrollo</profile.dir>             
            </properties>
        </profile>
        <profile>
            <id>pruebas</id>
            <properties>
                <profile.dir>src/main/profiles/pruebas</profile.dir>                
            </properties>
        </profile>
    </profiles>

3-. Tenemos que conseguir que Maven use y empaquete en el artefacto con el proyecto los ficheros ubicados en la ruta definida en la variable profile.dir. Además, no podemos olvidarnos de los que ya tenemos en la carpeta estándar para los recursos /src/main/resources/. Lo que haremos es configurar el plugin resources según las explicaciones de la documentación oficial:

<build>       
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>${profile.dir}</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

4-. Al ejecutar una orden, debemos indicar los perfiles a usar, separados por comas, con el parámetro -P:

mvn clean package -P desarrollo

Perfiles en los IDE

Los entornos de desarrollo integrado (IDE) compatibles con Maven deberían permitirnos seleccionar fácilmente los perfiles que queramos activar en cada momento. Es el caso de IntelliJ (mi favorito) y Eclipse IDE.

En IntelliJ, ya sea la versión Ultimate (de pago) o la Community (gratuita), tenemos una vista (View->Tool Windows) llamada Maven. Muestra los perfiles existentes en el pom para que podamos marcar los que queremos tener activos. En raras ocasiones, el cambio no surte efecto, y es necesario pulsar el botón Reload.

Para configurar los perfiles activos en Eclipse hay que acceder a la sección Maven dentro de las propiedades del proyecto (botón derecho sobre el proyecto).

eclipse maven profiles

Más cómodo: pulsando la combinación Control+Alt+P se mostrará la siguiente pantalla.

Activación automática de perfiles

Hemos visto cómo activar los perfiles mediante la línea de comandos. También se puede conseguir que los perfiles se activen de manera automática siguiendo seis estrategias. A continuación voy a resumirlas. Para más información, aquí tienes la documentación oficial.

Nota. Podemos comprobar los perfiles activos en un proyecto con el plugin help.

 mvn help:active-profiles
En el fichero settings.xml

Esta configuración es común para todos los proyectos que se construyan con la instalación de Maven que use ese settings.xml. En la sección activeProfiles declaramos aquellos perfiles que deben aplicarse cuando existan en el proyecto:

<activeProfiles>
    <activeProfile>windows</activeProfile>
</activeProfiles>
Según una variable de entorno

Se admiten tanto las variables establecidas en el sistema operativo como las propiedades proporcionadas al ejecutable de Maven con la opción -D.

Definimos la propiedad cuya presencia activa el perfil:

<profile>

    <activation>
        <property>
            <name>PROFILE</name>
         </property>
    </activation>

El criterio también puede ser la ausencia de la propiedad:

<profile>

    <activation>
        <property>
            <name>!PROFILE</name>
         </property>
    </activation>

O un valor exacto:

<profile>

    <activation>
        <property>
            <name>PROFILE</name>
            <value>dev</value>
         </property>
    </activation>
Chequear la existencia de un fichero
<profile>
  
    <activation>
         <file>
            <exists>src/main/resources/custom/profile.dev</exists>
         </file>
    </activation>

La ausencia se comprueba con missing en lugar de exists.

De forma predeterminada
<profile>
  
    <activation>
        <activeByDefault>true</activeByDefault>
    </activation>
Según el sistema operativo

Lo que sigue es un ejemplo real:

<profiles>
    <profile>
        <id>test-windows-docker-url</id>
            <activation>
                <os>
                    <family>windows</family>
                </os>
            </activation>

Lo encontrarás en los pom de los proyectos del Curso Jakarta EE. En ellos uso Arquillian Cube para ejecutar pruebas de integración que precisan de contenedores Docker. Necesito añadir una configuración específica cuando los tests se ejecuten en Windows.

Se puede indicar con más exactitud el sistema operativo con estas propiedades del plugin Maven Enforcer.

Según la versión de Java que use Maven
<profile>
  
    <activation>
        <jdk>11</jdk>
    </activation>

El valor de jdk es el comienzo del número de la versión. En el ejemplo, se admiten todas las de la serie 11 (11.0.1, 11.0.2, etcétera), pero no las superiores. Si queremos cubrir un grupo de jdks, debemos definir un rango según el formato explicado aquí. Por ejemplo, la siguiente activación se efectúa si Maven usa Java 11 o superior.

<activation>
    <jdk>[11,)</jdk>
</activation>

Desactivación de perfiles

La activación automática de tipo activeByDefault no se realiza cuando se indican los perfiles a aplicar con -P. Las demás, se activan siempre que se cumplan las condiciones definidas. Es posible evitar su activación con -P añadiendo el caracter «!» al nombre del perfil:

mvn package -P !profile,developer

La orden anterior empaqueta el proyecto aplicando el perfil developer y asegura que no se active el perfil profile.

Código de ejemplo

El proyecto se encuentra en GitHub. Para más información sobre cómo utilizar GitHub, consultar este artículo.

Deja una respuesta

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Salir /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Salir /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Salir /  Cambiar )

Conectando a %s

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.