Crear un JAR con dependencias con Apache Maven
¿Qué es un JAR con dependencias? Un requisito típico de los proyectos es agregar la salida junto con sus dependencias, módulos y otros archivos en…
Maven se basa en el concepto central de un ciclo de vida de construcción. Lo que esto significa es que el proceso para construir y distribuir un artefacto en particular, es decir, un proyecto está claramente definido. Para la persona que construye un proyecto solo es necesario aprender un pequeño conjunto de comandos para construir cualquier proyecto de Maven, y el POM se asegurará de que obtenga los resultados que desea.
Hay tres ciclos de vida de compilación integrados: default, clean y site.
default: maneja la construcción y el despliegue del proyecto.clean: limpia los archivos y carpetas producidos por Maven.site: maneja la creación de la documentación del proyecto.Cuando ejecutamos el comando mvn package para construir un proyecto Maven se puede observar cómo se ejecutan una serie de pasos. Si nos fijamos en estos pasos notaremos que no tenemos que especificar explícitamente un ciclo de vida. En cambio, lo que especificamos es una fase. Maven infiere el ciclo de vida en función de la fase especificada. Por ejemplo, la fase package indica que es el ciclo de vida default.
Cuando Maven se ejecuta con la fase package como parámetro, se ejecuta el ciclo de vida de compilación default. Maven ejecuta todas las fases en secuencia, hasta la fase especificada incluyendo a esta última (en nuestro caso, la fase package).
Si bien cada ciclo de vida tiene varias fases, veamos las fases importantes de cada ciclo de vida:
cleanLa fase clean elimina todos los archivos y carpetas creados por Maven como parte de su compilación. Por defecto, Maven almacena todos los archivos generados durante la compilación en el directorio target/. Al ejecutar la fase clean, este directorio se elimina por completo.
Para ejecutar este ciclo de vida, utilizamos el siguiente comando:
mvn clean
Tras la ejecución, veremos en la consola un mensaje similar a:
[INFO] --- maven-clean-plugin:3.2.0:clean (default-clean) @ mi-proyecto ---
[INFO] Deleting /ruta/del/proyecto/target
[INFO] BUILD SUCCESS
siteLa fase site genera la documentación del proyecto, que se puede publicar, así como una plantilla que se puede personalizar aún más. Esta documentación incluye informes sobre dependencias, plugins utilizados, licencias, y más.
Para generar la documentación del proyecto ejecutamos:
mvn site
Maven generará los archivos HTML de la documentación dentro del directorio target/site/. Podemos abrir el archivo target/site/index.html en un navegador para visualizar el sitio generado.
defaultLas siguientes son algunas de las fases importantes del ciclo de vida default. Es fundamental entender que Maven ejecuta las fases de forma secuencial: al invocar una fase, todas las fases anteriores se ejecutan primero. Por ejemplo, al ejecutar mvn package, Maven ejecutará automáticamente validate, compile, test y finalmente package.
Podemos ejecutar cualquiera de estas fases directamente desde la terminal:
mvn validate
mvn compile
mvn test
mvn package
mvn verify
mvn install
mvn deploy
validate: esta fase valida que toda la información del proyecto esté disponible y sea correcta.compile: esta fase compila el código fuente.test: esta fase ejecuta pruebas unitarias dentro de un marco adecuado.package: esta fase empaqueta el código compilado en su formato de distribución.verify: esta fase ejecuta controles para verificar que el paquete es válido.install: esta fase instala el paquete en el repositorio local.deploy: esta fase instala el paquete final en el repositorio configurado.A continuación compartimos una tabla de fases, plugins y goals:
| Fase | Plugin | Goal |
|---|---|---|
clean |
Maven Clean plugin | clean |
site |
Maven Site plugin | site |
process-resources |
Maven Resources plugin | resource |
compile |
Maven Compiler plugin | compile |
test |
Maven Surefire plugin | test |
package |
Varía según el empaquetado; por ejemplo, Maven JAR plugin | jar (en el caso del Maven JAR plugin) |
install |
Maven Install plugin | install |
deploy |
Maven Deploy plugin | deploy |
Maven permite ejecutar múltiples ciclos de vida en un solo comando. Uno de los comandos más utilizados en el día a día es:
mvn clean install
Este comando ejecuta primero el ciclo de vida clean (eliminando el directorio target/) y luego el ciclo de vida default hasta la fase install. Esto garantiza una compilación limpia desde cero, evitando posibles conflictos con archivos generados en compilaciones anteriores.
Otro ejemplo común es:
mvn clean package -DskipTests
Este comando limpia el proyecto, lo compila y lo empaqueta, pero omite la ejecución de pruebas unitarias. El flag -DskipTests es útil cuando necesitamos generar el artefacto rápidamente y ya hemos verificado que las pruebas pasan.
También podemos combinar los tres ciclos de vida en un solo comando:
mvn clean install site
Esto limpiará el proyecto, lo compilará e instalará en el repositorio local, y finalmente generará la documentación del sitio.
Un concepto clave para entender los ciclos de vida de Maven es la relación entre fases, plugins y goals.
Cada fase del ciclo de vida por sí sola no realiza ninguna tarea. En cambio, cada fase delega el trabajo real a un plugin de Maven. Un plugin es un componente que contiene uno o más goals (objetivos), donde cada goal es una tarea específica que el plugin puede ejecutar.
Cuando Maven llega a una fase durante la ejecución del ciclo de vida, busca qué plugin y goal están vinculados (o «bound») a esa fase y los ejecuta. Por ejemplo:
compile está vinculada al goal compile del Maven Compiler plugin.test está vinculada al goal test del Maven Surefire plugin.package está vinculada al goal jar del Maven JAR plugin (cuando el empaquetado es jar).Esta vinculación se define en el POM del proyecto, aunque Maven proporciona vinculaciones predeterminadas según el tipo de empaquetado. Por ejemplo, para un proyecto con empaquetado jar, la configuración predeterminada ya incluye las vinculaciones mostradas en la tabla anterior.
También es posible ejecutar un goal de un plugin sin pasar por el ciclo de vida. Para ello, se utiliza la sintaxis plugin:goal:
mvn compiler:compile
Este comando ejecuta únicamente el goal compile del Maven Compiler plugin, sin ejecutar las fases anteriores del ciclo de vida. Esto puede ser útil en escenarios de depuración, pero en la práctica diaria es más común trabajar con las fases del ciclo de vida.
El archivo pom.xml es donde se configura el comportamiento de los ciclos de vida para cada proyecto. En él podemos definir el tipo de empaquetado, las dependencias, y la configuración de los plugins.
Un pom.xml básico se ve así:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ejemplo</groupId>
<artifactId>mi-proyecto</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
El elemento <packaging> determina qué plugins y goals se vinculan a las fases del ciclo de vida default. Los valores más comunes son jar, war, pom y ear. Cada tipo de empaquetado tiene sus propias vinculaciones predeterminadas.
Por ejemplo, si cambiamos el empaquetado a war, la fase package se vinculará automáticamente al goal war del Maven WAR plugin en lugar del Maven JAR plugin.
Al trabajar con los ciclos de vida de Maven, es recomendable tener en cuenta lo siguiente:
clean antes de compilar para producción: El comando mvn clean package o mvn clean install garantiza que no haya archivos obsoletos del directorio target/ que puedan interferir con la compilación actual.-DskipTests es útil para compilaciones rápidas durante el desarrollo, en ambientes de integración continua (CI/CD) las pruebas deben ejecutarse siempre.install solo cuando sea necesario: La fase install copia el artefacto al repositorio local (~/.m2/repository). Si no necesitas que otros proyectos locales dependan de ese artefacto, package es suficiente.mvn compile package — con solo mvn package es suficiente, ya que compile se ejecutará automáticamente antes.