Primeros pasos con Maven
Contenido
Descarga e instala Maven
Descargue Maven y siguen las instrucciones de instalación (para Windows puedes usar estas). Tras instalar, ejecute
mvn --version
Si todo está correcto, debería observar algo como lo que sigue:
Apache Maven 3.3.3
Maven home: C:\...\apache-maven-3.3.3\bin\..
Java version: 1.8.0_25, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk1.8.0_25\jre
Default locale: es_ES, platform encoding: Cp1252
OS name: "windows 7", version: "6.1", arch: "amd64", family: "dos"
Cambiar la configuración de usuario del repositorio local para no contener espacios (opcional)
Hay tres niveles de configuración: instalación (mavenInst/conf/settings.xml), usuario (userHome/.m2/settings.xml), proyecto (projectHome/pom.xml)
Por defecto, el repositorio local está en ${user.home}/.m2/repository. Si se desea cambiar (para no contener espacios), en la carpeta ${user.home}/.m2 crear un archivo settings.xml con el siguiente contenido.
<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd">
<localRepository> nuevaRuta </localRepository>
</settings>
Generar el primer proyecto. El archetype utilizado por defecto es el maven-archetype-quickstart
mvn -B archetype:generate -DgroupId=es.egc.app -DartifactId=proy1
ó
mvn -B archetype:generate -DgroupId=es.egc.app -DartifactId=proy1 -DarchetypeArtifactId=maven-archetype-quickstart
Maven utiliza la convención de ficheros para encontrar los diferentes elementos del proyecto (cf. Ficheros). De este modo, todos los proyectos que usan maven deben seguir la misma estructura. Esto es conveniente pues asegura que cualquier desarrollador puede entender la estructura de directorios de un proyecto con mayor facilidad.
Siguiendo esta convención, la carpeta generada debido al arquetipo seleccionado tendrá el siguiente contenido:
- src/main contiene el código fuente
- src/test contiene el código para testeo
- un fichero pom.xml con la configuración del proyecto en Maven. El contenido de este fichero será el siguiente:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>es.egc.app</groupId>
<artifactId>proy1</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>proy1</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Lo que define este pom.xml es lo siguiente:
- groupId y artifactId, que son un identificador del proyecto y juega un papel similar al de los paquetes en Java.
- packaging, que establece el tipo de empaquetado que va a tener el proyecto. Por defecto es
jar
. - version, que fija la versión actual del proyecto.
- name, que da un nombre descriptivo al proyecto. No sirve para identificar el proyecto (para eso está el groupId y artifactId). Simplemente sirve para dar una descripción orientada a humanos.
- dependencies, que especifica las dependencias del proyecto. En este caso, se incluye la dependencia a JUnit.
Maven ofrece dos funcionalidades básicas:
- Gestión de la construcción de un proyecto
- Gestión de las dependencias de un proyecto
Ambas funcionalidades se configuran a través del fichero pom.xml
Plugins y objetivos
Un concepto clave de Maven son los plugins. Toda la funcionalidad de Maven se realiza a través de plugins. Hay plugins encargados de gestionar las dependencias, plugins encargados de compilar código Java, plugins encargados de ejecutar pruebas de JUnit, plugins encargados de empaquetar el código en un fichero JAR, etc. Los plugins ofrecen su funcionalidad a través de lo que se conoce como objetivos (goals). Por ejemplo, el plugin encargado de la compilación de código (compiler) tiene dos objetivos:
- compiler:compile que compila el código fuente del proyecto, que está en la carpeta main/src/java
- compiler:testCompile que compila el código de las pruebas del proyecto, que está en la carpeta main/src/test
Otro ejemplo puede ser el plugin encargado de crear un paquete JAR (jar), que tiene también dos objetivos:
- jar:jar que crea un fichero jar con el código del proyecto y el contenido de la carpeta src/main/resources
- jar:test-jar que crea un fichero jar con el código de las pruebas del proyecto y el contenido de la carpeta src/test/resources
Los plugins se pueden configurar en el fichero pom.xml del proyecto y los objetivos de un plugin se pueden invocar por línea de comandos de la siguiente forma:
mvn plugin1:objetivo1..pluginN:objetivoN
Los objetivos se ejecutan siguiendo el orden en que son invocados. Por tanto se podría hacer:
mvn compiler:compile jar:jar
Para compilar el código de nuestro proyecto y empaquetarlo en un JAR.
Ciclo de vida y fases
El otro concepto fundamental de Maven para la gestión de la construcción de un proyecto es el ciclo de vida. Un ciclo de vida está compuesto por un conjunto de fases. En Maven se definen tres ciclos de vida por defecto y normalmente nunca te vas a ver en la necesidad de definir ninguno adicional. Los tres ciclos de vida de Maven son:
- El ciclo de vida default, que gestiona la construcción y despliegue del proyecto.
- El ciclo de vida clean, que gestiona la limpieza del directorio del proyecto. Es decir, se encarga de eliminar todos los archivos generados en el proceso de construcción y despliegue.
- El ciclo de vida site, que gestiona la creación de la documentación del proyecto.
Las fases que componen cada ciclo de vida también están predefinidas. Por ejemplo, el ciclo de vida default está compuesto por las siguientes fases:
validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy
De entre todas ellas las más relevantes son:
- validate: Que valida que el proyecto es correcto y que está disponible toda la información necesaria
- compile: Que compila el código fuente del proyecto
- test: Que prueba el código compilado utilizando algún framework de pruebas unitarias. Estas pruebas no deben requerir que el código esté empaquetado o desplegado.
- package: Coge el código compilado y lo empaqueta en un formato distribuible. Por ejemplo, como un JAR.
- verify: Ejecuta comprobaciones de pruebas de integración para asegurarse que se cumplen los criterios de calidad
- install: Instala el paquete en el repositorio local (el directorio ${user.home}/.m2) para que se pueda usar como dependencia en otros proyectos localmente
- deploy: Copia el paquete final a un repositorio remoto para compartirlo con otros desarrolladores. Hay que tener en cuenta que este despliegue no se refiere en general al despliegue de la aplicación en un servidor web, sino a dejarlo disponible en un repositorio para que lo usen otros desarrolladores (más información en [Introducción de dependencias]).
En Lifecycles se recogen todas las fases definidas en cada ciclo de vida y una breve descripción de cada una de ellas.
Aunque cada fase es responsable de un paso específico en el ciclo de vida al que corresponda, la manera en la que se realizan esas responsabilidades puede variar en función del tipo de proyecto (ej. si es un proyecto web, una aplicación de consola, una librería, una aplicación de móviles...), del tipo de empaquetado utilizado (ej. si es WAR, JAR, EAR...), etc. Para configurar qué se hace en cada fase, cada fase se enlaza con uno o más objetivos de plugins. De este modo, ejecutar una fase del ciclo de vida equivale a ejecutar los objetivos de plugins vinculados a esa fase. Algunas fases tienen ya vinculadas objetivos de plugins por defecto. Esta vinculación varía dependiendo del tipo de packaging del proyecto. Por ejemplo, para un packaging jar, las fases con objetivos de plugin vinculados son las siguientes (puedes ver la lista completa en Built-in Lifecycle Bindings):
Fase | Plugin:objetivo |
process-resources | resources:resources |
compile | compiler:compile |
process-test-resources | resources:testResources |
test-compile | compiler:testCompile |
test | surefire:test |
package | jar:jar |
install | install:install |
deploy | deploy:deploy |
Además, esa vinculación se puede configurar a través del fichero pom.xml.
Un ciclo de vida no se ejecuta directamente por línea de comandos, sino que lo que se ejecuta esa una fase del ciclo de vida. La forma de ejecutarlo es igual que los objetivos de plugins:
mvn fase1..faseN
Cuando se ejecuta una fase, se ejecutan también todas las fases previas definidas en el ciclo de vida. Por tanto, si ejecutamos:
mvn package
Se ejecutaran todas las fases del ciclo de vida default desde la primera, que es validate, hasta package, incluyendo por tanto: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package.
Todas las fases que no tengan objetivos de plugins vinculados (por defecto, todas las que no están en negrita) simplemente se ignoran durante la ejecución.
En una misma llamada a Maven es posible mezclar fases con objetivos de plugins. Como siempre, el orden en que se ejecutan es el que aparecen en línea de comandos. Por ejemplo:
mvn clean dependency:copy-dependencies package
Lo que hace es:
- Invocar a la fase clean del ciclo de vida clean, que limpia el directorio del proyecto de todos los ficheros generados durante la construcción del mismo.
- Invocar al objetivo copy-dependencies del plugin dependency, que lo que hace es copiar los JAR de los que depende del proyecto a una carpeta dentro del mismo.
- Invocar a la fase package del ciclo de vida default, que compila, prueba y empaqueta el proyecto.
Ejercicio
Compilar el proyecto
mvn compile
Buscará los fuentes en src/main y las clases compiladas las situará en target/classes. Ambas son convenciones empleadas por maven.
Modificar el proyecto
- Introducir método en la clase App.java
static int getVal(){
return 1;
}
- Modificar test de la clase AppTest.java
…
assertTrue(App.getVal()==1);
…
Testear el proyecto
mvn test
Buscará los fuentes en src/test
Introducir error en el test y tratar de generar el .jar
mvn package
Resuelve el error introducido y genera el .jar
Observa como el JAR obtenido está en la carpeta target. En general, en maven, todos los resultados del proceso de construcción de nuestro proyecto va a ir a la carpeta target. Por esta razón, es conveniente añadir esta carpeta en el .gitignore (o equivalente) de nuestro sistema de control de versiones.