Tutorial di Apache Maven

1. Introduzione

La creazione di un progetto software consiste in genere in attività come il download di dipendenze, l'inserimento di file jar aggiuntivi su un percorso di classe, la compilazione del codice sorgente in codice binario, l'esecuzione di test, il confezionamento di codice compilato in artefatti distribuibili come file JAR, WAR e ZIP e la distribuzione di questi artefatti a un server delle applicazioni o un repository.

Apache Maven automatizza queste attività, riducendo al minimo il rischio che gli umani commettano errori durante la creazione manuale del software e separando il lavoro di compilazione e impacchettamento del nostro codice da quello di costruzione del codice.

In questo tutorial, esploreremo questo potente strumento per descrivere, creare e gestire progetti software Java utilizzando un'informazione centrale - il Project Object Model (POM) - scritto in XML.

2. Perché utilizzare Maven?

Le caratteristiche principali di Maven sono:

  • semplice configurazione del progetto che segue le migliori pratiche: Maven cerca di evitare il maggior numero di configurazioni possibile, fornendo modelli di progetto (denominati archetipi )
  • gestione delle dipendenze: include l'aggiornamento automatico, il download e la convalida della compatibilità, nonché la segnalazione delle chiusure delle dipendenze (note anche come dipendenze transitive)
  • isolamento tra dipendenze del progetto e plug-in: con Maven, le dipendenze del progetto vengono recuperate dai repository delle dipendenze mentre le dipendenze di qualsiasi plug-in vengono recuperate dai repository dei plug-in, con conseguente minor numero di conflitti quando i plug-in iniziano a scaricare dipendenze aggiuntive
  • sistema di repository centrale: le dipendenze del progetto possono essere caricate dal file system locale o da repository pubblici, come Maven Central
Per imparare come installare Maven sul tuo sistema, controlla questo tutorial su Baeldung.

3. Modello a oggetti del progetto

La configurazione di un progetto Maven avviene tramite un Project Object Model (POM) , rappresentato da un file pom.xml . Il POM descrive il progetto, gestisce le dipendenze e configura i plugin per la creazione del software.

Il POM definisce anche le relazioni tra i moduli dei progetti multi-modulo. Diamo un'occhiata alla struttura di base di un tipico file POM :

 4.0.0 org.baeldung org.baeldung jar 1.0-SNAPSHOT org.baeldung //maven.apache.org   junit junit 4.12 test      //...    

Diamo uno sguardo più da vicino a questi costrutti.

3.1. Identificatori di progetto

Maven utilizza una serie di identificatori, chiamati anche coordinate, per identificare in modo univoco un progetto e specificare come deve essere impacchettato l'artefatto del progetto:

  • groupId : un nome di base univoco della società o del gruppo che ha creato il progetto
  • artifactId : un nome univoco del progetto
  • version - una versione del progetto
  • packaging - un metodo di packaging (es. WAR / JAR / ZIP )

I primi tre di questi ( groupId: artifactId: version ) si combinano per formare l'identificatore univoco e sono il meccanismo con il quale si specifica quali versioni di librerie esterne (ad esempio JAR) verranno utilizzate dal progetto.

3.2. Dipendenze

Queste librerie esterne utilizzate da un progetto sono chiamate dipendenze. La funzionalità di gestione delle dipendenze in Maven garantisce il download automatico di tali librerie da un repository centrale, quindi non è necessario archiviarle localmente.

Questa è una caratteristica chiave di Maven e offre i seguenti vantaggi:

  • utilizza meno spazio di archiviazione riducendo significativamente il numero di download dai repository remoti
  • rende più veloce il check out di un progetto
  • fornisce una piattaforma efficace per lo scambio di artefatti binari all'interno della tua organizzazione e oltre senza la necessità di costruire artefatti dalla fonte ogni volta

Per dichiarare una dipendenza da una libreria esterna, è necessario fornire groupId, artifactId e la versione della libreria. Diamo un'occhiata a un esempio:

 org.springframework spring-core 4.3.5.RELEASE 

Man mano che Maven elabora le dipendenze, scaricherà la libreria Spring Core nel tuo repository Maven locale.

3.3. Archivi

A repository in Maven is used to hold build artifacts and dependencies of varying types. The default local repository is located in the .m2/repository folder under the home directory of the user.

If an artifact or a plug-in is available in the local repository, Maven uses it. Otherwise, it is downloaded from a central repository and stored in the local repository. The default central repository is Maven Central.

Some libraries, such as JBoss server, are not available at the central repository but are available at an alternate repository. For those libraries, you need to provide the URL to the alternate repository inside pom.xml file:

  JBoss repository //repository.jboss.org/nexus/content/groups/public/  

Please note that you can use multiple repositories in your projects.

3.4. Properties

Custom properties can help to make your pom.xml file easier to read and maintain. In the classic use case, you would use custom properties to define versions for your project's dependencies.

Maven properties are value-placeholders and are accessible anywhere within a pom.xml by using the notation ${name}, where name is the property.

Let's see an example:

 4.3.5.RELEASE    org.springframework spring-core ${spring.version}   org.springframework spring-context ${spring.version}  

Now if you want to upgrade Spring to a newer version, you only have to change the value inside theproperty tag and all the dependencies using that property in their tags will be updated.

Properties are also often used to define build path variables:

 ${project.build.directory}/tmp/   //... ${project.resources.build.folder} //... 

3.5. Build

The build section is also a very important section of the Maven POM. It provides information about the default Maven goal, the directory for the compiled project, and the final name of the application. The default build section looks like this:

 install ${basedir}/target ${artifactId}-${version}  filters/filter1.properties  //... 

The default output folder for compiled artifacts is named target, and the final name of the packaged artifact consists of the artifactId and version, but you can change it at any time.

3.6. Using Profiles

Another important feature of Maven is its support for profiles. A profile is basically a set of configuration values. By using profiles, you can customize the build for different environments such as Production/Test/Development:

  production    //...      development  true     //...     

As you can see in the example above, the default profile is set to development. If you want to run the production profile, you can use the following Maven command:

mvn clean install -Pproduction

4. Maven Build Lifecycles

Every Maven build follows a specified lifecycle. You can execute several build lifecyclegoals, including the ones to compile the project’s code, create a package, and install the archive file in the local Maven dependency repository.

4.1. Lifecycle Phases

The following list shows the most important Maven lifecycle phases:

  • validate – checks the correctness of the project
  • compile – compiles the provided source code into binary artifacts
  • test – executes unit tests
  • package – packages compiled code into an archive file
  • integration-test – executes additional tests, which require the packaging
  • verify – checks if the package is valid
  • install – installs the package file into the local Maven repository
  • deploy – deploys the package file to a remote server or repository

4.2. Plugins and Goals

A Maven plugin is a collection of one or more goals. Goals are executed in phases, which helps to determine the order in which the goals are executed.

The rich list of plugins that are officially supported by Maven is available here. There is also an interesting article how to build an executable JAR on Baeldung using various plugins.

To gain a better understanding of which goals are run in which phases by default, take a look at the default Maven lifecycle bindings.

To go through any one of the above phases, we just have to call one command:

mvn 

For example, mvn clean install will remove the previously created jar/war/zip files and compiled classes (clean) and execute all the phases necessary to install new archive (install).

Please note that goals provided by plugins can be associated with different phases of the lifecycle.

5. Your First Maven Project

In this section, we will use the command line functionality of Maven to create a Java project.

5.1. Generating a Simple Java Project

In order to build a simple Java project, let's run the following command:

mvn archetype:generate -DgroupId=org.baeldung -DartifactId=org.baeldung.java -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

The groupId is a parameter indicating the group or individual that created a project, which is often a reversed company domain name. The artifactId is the base package name used in the project, and we use the standard archetype.

Since we didn't specify the version and the packaging type, these will be set to default values — the version will be set to 1.0-SNAPSHOT, and the packaging will be set to jar.

If you don't know which parameters to provide, you can always specify interactiveMode=true, so that Maven asks for all the required parameters.

After the command completes, we have a Java project containing an App.java class, which is just a simple “Hello World” program, in the src/main/java folder.

We also have an example test class in src/test/java. The pom.xml of this project will look similar to this:

 4.0.0 org.baeldung org.baeldung.java jar 1.0-SNAPSHOT org.baeldung.java //maven.apache.org   junit junit 4.1.2 test   

As you can see, the junit dependency is provided by default.

5.2. Compiling and Packaging a Project

The next step is to compile the project:

mvn compile

Maven will run through all lifecycle phases needed by the compile phase to build the project's sources. If you want to run only the test phase, you can use:

mvn test

Now let's invoke the package phase, which will produce the compiled archive jar file:

mvn package

5.3. Executing an Application

Finally, we are going to execute our Java project with the exec-maven-plugin. Let's configure the necessary plugins in the pom.xml:

 src   maven-compiler-plugin 3.6.1  1.8 1.8    org.codehaus.mojo exec-maven-plugin 1.5.0  org.baeldung.java.App    

The first plugin, maven-compiler-plugin, is responsible for compiling the source code using Java version 1.8. The exec-maven-plugin searches for the mainClass in our project.

To execute the application, we run the following command:

mvn exec:java

6. Multi-Module Projects

The mechanism in Maven that handles multi-module projects (also called aggregator projects) is called Reactor.

The Reactor collects all available modules to build, then sorts projects into the correct build order, and finally, builds them one by one.

Let's see how to create a multi-module parent project.

6.1. Create Parent Project

First of all, we need to create a parent project. In order to create a new project with the name parent-project, we use the following command:

mvn archetype:generate -DgroupId=org.baeldung -DartifactId=parent-project

Next, we update the packaging type inside the pom.xml file to indicate that this is a parent module:

pom

6.2. Create Submodule Projects

In the next step, we create submodule projects from the directory of parent-project:

cd parent-project mvn archetype:generate -DgroupId=org.baeldung -DartifactId=core mvn archetype:generate -DgroupId=org.baeldung -DartifactId=service mvn archetype:generate -DgroupId=org.baeldung -DartifactId=webapp

To verify if we created the submodules correctly, we look in the parent-project pom.xml file, where we should see three modules:

 core service webapp 

Moreover, a parent section will be added in each submodule’s pom.xml:

 org.baeldung parent-project 1.0-SNAPSHOT 

6.3. Enable Dependency Management in Parent Project

Dependency management is a mechanism for centralizing the dependency information for a muti-module parent project and its children.

When you have a set of projects or modules that inherit a common parent, you can put all the required information about the dependencies in the common pom.xml file. This will simplify the references to the artifacts in the child POMs.

Let's take a look at a sample parent's pom.xml:

   org.springframework spring-core 4.3.5.RELEASE  //...  

By declaring the spring-core version in the parent, all submodules that depend on spring-core can declare the dependency using only the groupId and artifactId, and the version will be inherited:

  org.springframework spring-core  //... 

Moreover, you can provide exclusions for dependency management in parent's pom.xml, so that specific libraries will not be inherited by child modules:

  org.springframework spring-context  

Finally, if a child module needs to use a different version of a managed dependency, you can override the managed version in child's pom.xml file:

 org.springframework spring-core 4.2.1.RELEASE 

Please note that while child modules inherit from their parent project, a parent project does not necessarily have any modules that it aggregates. On the other hand, a parent project may also aggregate projects that do not inherit from it.

For more information on inheritance and aggregation please refer to this documentation.

6.4. Updating the Submodules and Building a Project

We can change the packaging type of each submodule. For example, let's change the packaging of the webapp module to WAR by updating the pom.xml file:

war

Now we can test the build of our project by using the mvn clean install command. The output of the Maven logs should be similar to this:

[INFO] Scanning for projects... [INFO] Reactor build order: [INFO] parent-project [INFO] core [INFO] service [INFO] webapp //............. [INFO] ----------------------------------------- [INFO] Reactor Summary: [INFO] ----------------------------------------- [INFO] parent-project .................. SUCCESS [2.041s] [INFO] core ............................ SUCCESS [4.802s] [INFO] service ......................... SUCCESS [3.065s] [INFO] webapp .......................... SUCCESS [6.125s] [INFO] -----------------------------------------

7. Conclusion

In questo articolo, abbiamo discusso alcune delle funzionalità più popolari dello strumento di compilazione Apache Maven.

Tutti gli esempi di codice su Baeldung sono creati utilizzando Maven, quindi puoi facilmente controllare il nostro sito Web del progetto GitHub per vedere varie configurazioni di Maven.