Maven

 

¿ Qué es Maven ?

Maven es una herramienta principalmente utilizada en el desarrollo de software Java. Aparece ante la necesidad de modelar el concepto de "proyecto" y artefacto en forma estándar independendientemente del IDE de desarrollo.

Se utiliza como herramienta de SCM (Software Configuration Management) para controlar
  • el versionado de nuestros proyectos,
  • las dependencias con proyectos nuestros y librerías de terceros
  • y para la automatización de tareas relativas al ambiente de desarrollo y construcción del artefacto (compilación, generación de código, empaquetado, etc) 

Funciones Principales

Maven cumple con las siguientes funciones principales que vamos a explicar en las siguientes secciones:
  • Reificación de Proyecto / Artefacto en forma standard, declarativa y extensible.
  • Manejo de Dependencias.
  • Manejo del Ciclo de Vida del Artefacto, incluyendo releases.
  • Documentación y Comunicación

Reificación de Proyecto/Artefacto

Ya habíamos visto que la idea de proyecto no proviene de Java, sino que es un agregado de Eclipse como IDE. Por este motivo se trabaja con
  • .classpath (directorios donde compilar y dependencias del proyecto)
  • .project (nombre del proyecto, entre otras cosas)
como archivos de proyecto propios de Eclipse. Si nosotros trabajamos con otro IDE (como NetBeans o IntelliJ) tenemos que adaptar estos archivos para generar el proyecto con sus dependencias adecuadamente.
 
Maven permite trabajar entre IDEs con su propio modelo de proyecto: ya no es necesario subir al SVN los archivos .classpath y .project .
 
Todo proyecto maven se constituye de un archivo XML llamado pom.xml (de Project Object Model): éste es el archivo que tenemos que subir al SVN.

En este archivo, por ahora vamos a contar que lo más importante es que se declara un identificador único de nuestro proyecto/artefacto, que resulta de la unión de tres identificadores:
  • groupId : representa la organización autora/dueña del artefacto. Por ejemplo: com.ibm, org.apache, org.jboss, etc. Este id por sí mismo no identifica un artefacto por las razones obvias de que una organización puede tener más de un artefacto.
  • artifactId : nombre del proyecto/artefacto actual. Por ejemplo: http-client, hibernate, tomcat, commons-collections, etc.
  • version : como su nombre dice, identifica al número de versión del artefacto.
A continuación un ejemplo básico.

<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>com.uqbar</groupId>
    <artifactId>uqbar-commons</artifactId>
    <version>1.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>Uqbar Commons Project</name>
</project>


Nótese que un artefacto no se podría identificar unívocamente con groupId + artifactId, ya que podrán existir múltiples versiones.

Acá introducimos una herramienta útil, el sitio Maven Repository.
Este sitio es básicamente un buscador de proyectos/artefactos maven, que estén públicos en internet. (Ya veremos más adelante el concepto de repositorios en la sección de dependencias).

Fíjense un artefacto bastante popular en la comunidad java de hoy en día es el framework spring. En http://mvnrepository.com/artifact/org.springframework/spring se ve que pueden existir bastaaaantes versiones de un artefacto, como en este caso.

Maven establece un estándar a nivel mundial. Tanto nuestros nuevos proyectos como todos los de la comunidad java+maven van a tener la misma estructura e identificación:

    <groupId>org.springframework</groupId>
    <artifactId>spring</artifactId>
    <version>2.5.6.SEC02</version>

TODO: Ejemplo para el TP 
 

Manejo de Dependencias

Además de identificar a nuestro proyecto unívocamente, el pom se utiliza para declarar diferentes aspectos y metadata de nuestros proyectos.

Nótese que decimos declarar no por casualidad, sino porque justamente una de las características más importantes de maven es que nos provee una forma declarativa de asociar metadata y configurar el ciclo de vida de nuestros proyectos.

Esta es una de las características principales que lo diferencian de otras herramientas anteriores como apache ant donde por cada proyecto nosotros codificábamos acciones a realizar sobre el proyecto (ant tasks) en una forma mucho más imperativa.

Entre otras cosas, una de las más importantes es que declaramos las dependencias respecto de otros artefactos.

<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">

...
    <dependencies>
         <dependency>
              <groupId>com.uqbar</groupId>
              <artifactId>uqbar-class-descriptor</artifactId>
              <version>1.1-SNAPSHOT</version>
         </dependency>
         <dependency>
              <groupId>com.uqbar</groupId>
              <artifactId>uqbar-bttf</artifactId>
              <version>2.2-SNAPSHOT</version>
         </dependency>
    </dependencies>
...
</project>

En este ejemplo estamos declarando dos dependencias a artefactos.

¿Para qué se declaran las dependencias?

Para varias cosas.
Pero la más importante es que ahora con el pom.xml ya podemos saber qué pre-requisitos necesitamos para trabajar en este proyecto (para compilar).

Entonces, como dijimos en un principio, groupId+artifactId+version identifican un artefacto unívocamente. Si existiera alguien que guardara esas librerías, al que yo le pudiera decir "dame el jar de com.uqbar:uqbar-class-descriptor:1.1-SNAPSHOT" y me lo supiera dar, entonces, no haría falta que tengamos que bajarnos los jars "a mano", ni que los tengamos que versionar (subir al subversion o cualquier otra herramienta para versionado de código).

Ese "alguien" existe, y son los repositorios maven.


La forma de utilizarlos es a través de la herramienta "maven". Que es algo así como el cliente de svn. Es decir es una herramienta de línea de comandos (después vamos a ver que existen plugins de eclipse que nos evitan utilizar la linea de comando -a veces-).

Existe un repositorio de maven público llamado "ibiblio" o "repo1" que contiene muchísimos proyectos open-source. Es el que figura en la imagen.
Entonces una cosa que hace maven es bajarse los jars de las dependencias automáticamente de internet.

Para eso podemos ejecutar un goal básico de maven (Ver siguiente sección) en la misma carpeta del proyecto.

mvn clean compile


Lo cual va a producir en la consola mensajes parecidos a estos:

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building TestWebapp Maven Webapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.4.1/maven-clean-plugin-2.4.1.pom
Downloaded: http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.4.1/maven-clean-plugin-2.4.1.pom (5 KB at 2.5 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.4.1/maven-clean-plugin-2.4.1.jar
Downloaded: http://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.4.1/maven-clean-plugin-2.4.1.jar (23 KB at 26.6 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/glassfish/web/jstl-impl/1.2/jstl-impl-1.2.pom
Downloaded: http://repo.maven.apache.org/maven2/org/glassfish/web/jstl-impl/1.2/jstl-impl-1.2.pom (8 KB at 10.5 KB/sec)
Downloaded: http://repo.maven.apache.org/maven2/javax/servlet/jsp/jsp-api/2.1/jsp-api-2.1.pom (157 B at 0.3 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/javax/servlet/jsp/jstl/jstl-api/1.2/jstl-api-1.2.pom
Downloaded: http://repo.maven.apache.org/maven2/javax/servlet/jsp/jstl/jstl-api/1.2/jstl-api-1.2.pom (5 KB at 6.6 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/commons-beanutils/commons-beanutils/1.7.0/commons-beanutils-1.7.0.jar
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ TestWebapp ---
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/2.0.5/plexus-utils-2.0.5.pom
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/2.0.5/plexus-utils-2.0.5.pom (4 KB at 5.3 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus/2.0.6/plexus-2.0.6.pom
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus/2.0.6/plexus-2.0.6.pom (17 KB at 18.3 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/2.0.5/plexus-utils-2.0.5.jar
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/2.0.5/plexus-utils-2.0.5.jar (218 KB at 77.1 KB/sec)
[INFO] 
[INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ TestWebapp ---
Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/maven-profile/2.0.6/maven-profile-2.0.6.pom
Downloaded: http://repo.maven.apache.org/maven2/org/apache/maven/maven-profile/2.0.6/maven-profile-2.0.6.pom (2 KB at 3.2 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact-manager/2.0.6/maven-artifact-manager-2.0.6.pom
Downloaded: http://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact-manager/2.0.6/maven-artifact-manager-2.0.6.pom (3 KB at 4.1 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-registry/2.0.6/maven-plugin-registry-2.0.6.pom
Downloaded: http://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-registry/2.0.6/maven-plugin-registry-2.0.6.pom (2 KB at 2.0 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/maven-error-diagnostics/2.0.6/maven-error-diagnostics-2.0.6.pom
Downloaded: http://repo.maven.apache.org/maven2/org/apache/maven/maven-error-diagnostics/2.0.6/maven-error-diagnostics-2.0.6.pom (2 KB at 1.4 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/commons-cli/commons-cli/1.0/commons-cli-1.0.pom
Downloaded: http://repo.maven.apache.org/maven2/commons-cli/commons-cli/1.0/commons-cli-1.0.pom (3 KB at 3.4 KB/sec)
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-components/1.1.15/plexus-components-1.1.15.pom (3 KB at 4.7 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus/2.0.3/plexus-2.0.3.pom
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus/2.0.3/plexus-2.0.3.pom (16 KB at 22.6 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/reporting/maven-reporting-api/2.0.6/maven-reporting-api-2.0.6.jar
[debug] execute contextualize
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ TestWebapp ---
Downloading: http://repo.maven.apache.org/maven2/org/apache/maven/maven-toolchain/1.0/maven-toolchain-1.0.pom
Downloaded: http://repo.maven.apache.org/maven2/org/apache/maven/maven-toolchain/1.0/maven-toolchain-1.0.pom (4 KB at 5.6 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-compiler-api/1.8.1/plexus-compiler-api-1.8.1.pom
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-compiler-api/1.8.1/plexus-compiler-api-1.8.1.pom (805 B at 1.3 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-compiler/1.8.1/plexus-compiler-1.8.1.pom
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-compiler/1.8.1/plexus-compiler-1.8.1.pom (4 KB at 5.7 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-components/1.1.18/plexus-components-1.1.18.pom
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-components/1.1.18/plexus-components-1.1.18.pom (6 KB at 8.3 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus/2.0.7/plexus-2.0.7.pom
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus/2.0.7/plexus-2.0.7.pom (17 KB at 24.7 KB/sec)
Downloading: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/1.5.5/plexus-utils-1.5.5.pom
Downloaded: http://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/1.5.5/plexus-utils-1.5.5.pom (6 KB at 6.8 KB/sec)
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 23 source files to /media/07995b1d-8f74-4fa0-9e9b-1c889f7fe5d9/development/data/repos/utn-tadp-projects/ajedrez/trunk/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 48.519s
[INFO] Finished at: Wed Sep 05 22:46:10 ART 2012
[INFO] Final Memory: 6M/15M
[INFO] ------------------------------------------------------------------------

Acá vemos varias cosas. La principal es entender los mensajes que aparecen al principio y al final, con esos separadores con caracteres asci  ( ---------)
Así maven nos dirá qué va a hacer (al principio) y sobre qué proyecto (el pom.xml del directorio actual) y al final nos va a indicar el resultado: SUCCESS o FAILED.

¿Qué hizo? Bueno, lo que le indicamos, ejecutó dos tareas, o como se llaman en maven, goals, que le indicamos como parámetros. 
  • clean: borra cualquier archivo generado previamente, como por ejemplo los .class resultado de la compilación. En la práctica lo que hace es borrar la carpeta "target" de nuetro proyecto, que es a donde va a parar todo el contenido generado.
  • compile: no hace falta explicar demasiado. Compiló al directorio target
En el medio, vemos un montón de mensajitos que arrancan con Downloading: ..... y Downloaded ....
Lo que hizo maven ahí fue leer nuestro pom y averiguar así, de qué otros proyectos/librerías/artefactos depende.
Entonces, por cada uno de estos hizo:
  • fue a buscar a un repositorio en internet el pom.xml de cada una de esas dependencias (ya vamos a hablar más adelante de esto). Por eso se ven algunos Downloading : http://blah.... asd.pom
  • fue a buscar el archivo jar de esta dependencia también a internet.
  • leyó el pom y así pudo averiguar, a su vez de qué otros proyectos depende este, y con cada uno de estos volvió a hacer esto mismo que contamos acá.

¿A dónde baja las dependencias maven ?

Para eso pasar a la sección "Repositorios Maven"

Dependencias Transitivas

Un detalle no-menor de la resolución de dependencias de maven es que también funciona para las dependencias transitivas.
Esto quiere decir que si nuestro proyecto A depende del proyecto B, maven automáticamente va a bajar el jar de proyectoB, pero además, todas las dependencias que este tenga.
Por ejemplo

  • proyectoA --> proyectoB
  • proyectoB --> proyectoC
  • proyectoC --> proyectoD & proyectoE & proyectoF
Al resolver dependencias:
  • proyectoA --> proyectoB, proyectoC, proyectoD, proyectoE, proyectoF
Esto parece trivial pero es muy importante. Porque en la era pre-maven debíamos buscar a mano y bajar cada una de las dependencias transitivas, y podía pasarnos que
  • una librería quizás no especificaba sus dependencias
  • o las versiones (¿commons-collections 1.5 ó 1.6?)
  • o los jars podían no estar públicos en internet.
Noten que un proyecto comercial "normal" o mediano, puede incluir decenas y hasta cientos de dependencias.
 
Ejecutando el siguiente goal de un plugin de maven, podemos ver el árbol de pendencias de nuestro proyecto

mvn dependency:tree
[INFO] edu.unsam.algo3:TestWebapp:war:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:3.8.1:test
[INFO] +- org.glassfish.web:jstl-impl:jar:1.2:compile
[INFO] |  +- javax.servlet:servlet-api:jar:2.5:compile
[INFO] |  +- javax.servlet.jsp:jsp-api:jar:2.1:compile
[INFO] |  \- javax.servlet.jsp.jstl:jstl-api:jar:1.2:compile
[INFO] +- com.thoughtworks.xstream:xstream:jar:1.2.2:compile
[INFO] |  \- xpp3:xpp3_min:jar:1.1.3.4.O:compile
[INFO] \- commons-beanutils:commons-beanutils:jar:1.7.0:compile
[INFO]    \- commons-logging:commons-logging:jar:1.0.3:compile

Ahí pueden ver las dependencias transitivas.
En este caso estamos hablando de un proyecto muy chiquito. 
 
Para más detalles del mecanismo de dependencias pueden ver la documentación del plugin acá

Ciclo de Build (goals)

Maven no sólo se utiliza para bajar jars de internet, sino para todo el ciclo de vida del proyecto.
Lo vamos a usar para compilar, para generar código (de ser necesario), para correr los tests, para empaquetar, y hasta para publicar nuestros artefactos generando releases con trazabilidad (ver conceptos relacionados con subversion y herramientas de versionado de código).

Maven define un conjunto de etapas en la construcción (build) de nuestro proyecto. Resumimos algunas acá:
  1. generate-sources: generar código, previo a compilación.
  2. compile: compila el código fuente.
  3. test: ejecuta los test cases
  4. package: genera un paquete con el código (.jar por ejemplo)
  5. install: hace público el paquete en nuestro repositorio local (ver repositorios locales en las siguiente sección)
  6. deploy: publica el artefacto en un repositorio remoto (ver repositorios locales en las siguiente sección)

Podemos indicar a maven que ejecute hasta cierta fase.
Por ejemplo:

mvn compile

Va a ejecutar las dos primeras fases.

mvn test


Las tres primeras. Es decir es igual a mvn compile + correr los tests

Para terminar de entender cómo funciona el ciclo de vida y la ejecución pasen a la sección "Arquitectura de Plug-ins"

Y por si les interesa profundizar un poco más, acá va un diagrama que muestra tooooodas las fases reales del ciclo de build de maven (como dijimos, las mencionadas arriba son sólo una parte)


Repositorios Maven

Un repositorio maven es básicamente un lugar donde están los artefactos maven, estructurados en cierta forma estándar que permitirá a maven hacer el download específico de las dependencias.

Existen tres tipos de repositorios. En realidad los tres son iguales en cuanto a que contienen artefactos.

  1. Repositorio Local: cada desarrollador al instalarse y usar maven (el comando) va a tener localmente, en su máquina, un repositorio. La herramienta maven, al resolver dependencias, buscándolas y bajándolas de internet, las va a ir cacheando es decir se las va a guardar para recordarlas y no tener que salir a buscarlas todo el tiempo. El repositorio por default se encuentra en la carpeta $HOME/.m2/repository Pero esto se puede modificar en $MAVEN/conf/settings.xml
  2. Repositorio Público de Internet: Es el repositorio de maven por default, donde la herramienta busca los artefactos. Es un servidor donde se encuentran hosteados (deployados) los proyectos open source más utilizados en la comunidad java. Uno podría publicar sus artefactos allí, aunque para eso tiene que cumplir con ciertos requerimientos de licencia (software libre y open source), y además seguir un proceso para que los artefactos sean aprobados, etc. En la práctica las empresas privadas que no quieran publicar sus artefactos, pero igualmente utilizar maven, deberán tener sus propios artefactos "empresariales" que se explican a continuación.
  3. Repositorio "Empresarial" (o repo remoto): en esta arquitectura, la empresa u organización requiere tener un repositorio maven propio, ya sea para publicar sus propios artefactos solo dentro de la organización, sin hacerlo público a toda internet, o bien para evitar que cada maven de cada desarrollador acceda a internet para bajarse los artefactos. Básicamente, se instalar una aplicación en un servidor, y luego se configura maven en cada máquina de los desarrolladores para que utilicen este repositorio.

El diagrama muestra el caso donde se están utilizando los 3 repositorios.
En cada máquina de cada desarrollador existirá un repositorio local. El servidor del centro es el repositorio empresarial, mientras que el de la derecha es el repositorio oficial de maven.

Es importante entender esta arquitectura física, porque los repositorios de maven son el medio que tenemos para publicar nuestros artefactos, ya sea para hacer un entregable (release) como también para hacer públicos nuestros cambios durante el desarrollo para otros desarrolladores.

Y acá entonces se explica un poco más el ciclo de vida de la sección anterior.

mvn install


Empaqueta el proyecto y lo publica en nuestro repositorio local. Hace un copy al repo loca $HOME/.m2/repository/com/blah/artifactBlah/1.0.0/artifactBlah-1.0.0,jar
Este comando se utiliza para publicar una nueva versión del jar y así poder utilizarla desde otro proyecto, pero dentro de nuestra máquina.

mvn deploy


Hace lo mismo que install + publica el artefacto en el repositorio remoto.
Este goal sí permite publicar el artefacto haciéndolo disponible para otros desarrolladores.


Arquitectura de Plug-ins

Maven tiene una arquitectura de plugins, lo cual quiere decir que está diseñado y compuesto de pequeñas partecitas o módulos llamados plug-ins. El nombre proviene del hecho de que esas partes se pueden ir agregando. Es decir que la arquitectura no es rígida sino extensible. De hecho, existe un API java pública, ya que maven está hecho en java, con la cual nosotros podemos hacer nuestros propios plugins de maven (llamados MOJOs).

Existen diferentes plug-ins, por ejemplo surefire es el que sabe correr los tests cases de junit. Maven va a bajarse los plugins automáticamente desde internet en la misma forma en que baja las dependencias por nosotros. Esto hace de maven una herramienta gloriosa que nos va a evitar muchísimo trabajo manual.

Los plugins proveen funcionalidades en forma de comandos que se pueden invocar, llamados goals.
Si conocen ant, sería algo similar a la idea de ant task.

Ejemplo:

mvn dependency:tree


Estamos ejecutando el goal "tree" del plugin llamado "dependency".
En este caso, esto mostrará el arbol de dependencias de artefactos en la consola.
[INFO] [dependency:tree]
[INFO] org.apache.maven.plugins:maven-dependency-plugin:maven-plugin:2.0-alpha-5-SNAPSHOT
[INFO] +- org.apache.maven.reporting:maven-reporting-impl:jar:2.0.4:compile
[INFO] | \- commons-validator:commons-validator:jar:1.2.0:compile
[INFO] | \- commons-digester:commons-digester:jar:1.6:compile
[INFO] | \- (commons-collections:commons-collections:jar:2.1:compile - omitted for conflict with 2.0)
[INFO] \- org.apache.maven.doxia:doxia-site-renderer:jar:1.0-alpha-8:compile
[INFO] \- org.codehaus.plexus:plexus-velocity:jar:1.1.3:compile
[INFO] \- commons-collections:commons-collections:jar:2.0:compile

Además de poder ejecutar un goal explícitamente, es decir pedirle a maven que ejecute un comando, se puede indicar que cierto goal debe ejecutarse en cierta fase del build. Y muchos plugins se "cuelgan" automáticamente en algunos pasos de modo de ejecutar automáticamente por convención (acá entra la idea de declaratividad).

Por ejemplo, el plugin surefire de junit va a ejecutar un goal en la fase test.

Entonces maven va ejecutando fases del build y en cada una de estas se meten los plugins para hacer cosas como compilar, generar código, correr los tests, etc. como se muestra en el siguiente diagrama:



Material de Referencia