Das Buildsystem Maven

https://oer-informatik.de/build-tool-maven

tl/dr; (ca. 15 min Lesezeit): Mit dem Buildtool Maven kann der Erstellungsprozess von Software automatisiert werden: Kompilieren, Testen, Packen und Veröffentlichen kann nach einem vorkonfigurietem Muster wiederholbar ablaufen. (Zuletzt geändert am 07.09.2023)

Softwareprojekte mit Java bestehen häufig nicht nur aus einzelnen Quellcodedateien, sondern aus einer Vielzahl verschachtelter Abhängigkeiten. Im Software-Erstellungsprozess müssen Code und Abhängigkeiten verwaltet, organsiert, die Applikation gebaut, getestet und veröffentlicht werden. Viele der nötigen Schritte sind automatisierbar und müssen nicht von Hand vorgenommen werden: das erledigen Build-Tools wie Ant, Gradle oder Maven automatisch. Jedes dieser Buildtools hat eigene Vorteile, derzeit sind Maven und Gradle die verbreitetsten im Java-Umfeld.

Die Build-Tools kümmern sich um den Prozess, der aus Quellcode und Abhängigkeiten Stück für Stück ein lauffähiges Programm baut, dieses testet, das auslieferbare Paket erzeugt (z.B. jar-Datei) und dieses schließlich veröffentlicht. Einige der Anwendungsfälle sind in folgendem Use-Case-Diagramm zusammengetragen:

Anwendungsfälle für das Build-Tool Maven
Anwendungsfälle für das Build-Tool Maven

Für die meisten dieser Schritte muss Maven nicht explizit konfiguriert werden, da das Designprinzip “Convention over Configuration” zum Zug kommt: der Standardweg ist bereits vorkonfiguriert.

Maven installieren

Auf den meisten Systemen ist Maven bereits vorhanden oder bei der Installation einer Entwicklungsumgebung mit installiert. Ob Maven bereits installiert ist (und im PATH des jeweiligen Betriebssystems eingetragen ist) lässt sich mit dem folgenden Befehl im Terminal / in der Powershell herausfinden:

Es sollte etwa die folgende Antwort kommen:

Maven home: C:\Program Files\apache-maven-bin\apache-maven-3.8.6
Java version: 17.0.4, vendor: Oracle Corporation, runtime: C:\Program Files\Java\jdk-17.0.4
Default locale: de_DE, platform encoding: Cp1252
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

Wenn als Antwort eine Fehlermeldung (oder eine deutlich ältere Version) kommt, lohnt ein Blick auf die Install-Anleitung von Maven. Hier wird auch erklärt, wie man überprüfen kann, ob der PATH stimmt und ob die korrekte Java-Version gefunden wird.

Maven im Schnelldurchgang

Um einmal zu verdeutlichen, wie Maven funktioniert, setzten wir den Gesamtprozess der Softwareerstellung mit Maven über die Konsole um. Das ist etwas umständlicher als nötig: schließlich nimmt uns normalerweise die Integrierten Entwicklungsumgebungen (IDE) viel Arbeit ab. Zum Beispiel bei der Projekterzeugung.

Wir erzeugen von Hand ein neues Projekt. Der Einfachheit halber nutzen wir dazu eine Maven-Vorlage (java11-archetype) mit dem Befehl:

Etwas übersichtlicher (aber nicht ausführbar) mit zeilenweisen Optionen:

Nachfolgend ist kurz erklärt, welche Optionen dieser Befehl nutzt. Wen das nicht interessiert, der möge diese Tabelle einfach überspringen (verzichtbares Wissen für gerade…):

Option Bedeutung
archetype:generate das Goal generate in dem Maven-Plugin archetype wird aufgerufen
-B Batchmode (ohne Rückfragen)
-D Es werden folgende Properties übergeben (die nachfolgenden Einträge)
archetypeGroupId=
"tech.raaf"
die genutzte Vorlage gehört zur folgenden Gruppe
archetypeArtifactId=
"java11-archetype"
die genutzte Vorlage heißt…
groupId=
"de.csbme.ifaxx"
die Gruppe des Projekts, kann frei gewählt werden, ist oft eine umgekehrte Domain und wird die Paket-Bezeichnung des Projekts
artifactId=
"myFirstMavenProject"
Name der Applikation, des Produkts

Es wird eine kurze Weile dauern bis Maven alle nötigen Dateien geladen hat. Lädt nichts und kommt ein Fehler? Dann müssen vielleicht die Proxyeinträge in der settings.xml angepasst werden.

Am Ende wiederholt Maven nochmal die oben übergebenen Parameter und beendet mit einer Erfolgsmeldung: BUILD SUCCESS:

[INFO] Parameter: ...
[INFO] Project created from Archetype in dir: C:\...\myFirstMavenProject
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.087 s
[INFO] Finished at: 2022-10-25T20:35:39+02:00
[INFO] ------------------------------------------------------------------------

Die Maven Ordnerstruktur

Mit einem Maven-Projekt wird auch die Ordnerstruktur angelegt. Auch wenn es hier zu Abweichungen zwischen einzelnen Projekten kommen kann, gibt es doch immer die Gemeinsamkeiten:

  • im Projektverzeichnis liegt die Datei pom.xml, die die wesentlichen Konfigurationsdaten enthält
  • im Unterverzeichnis ./src finden sich zwei spiegelbildliche Verzeichnisbäume für den Application-Sourcecode (./src/main/java) und für die Tests (./src/test/java)
  • Später wird noch ein Ordner ./target eingerichtet, in dem die Artefakte zur Veröffentlichung gespeichert werden (Produkt und Dokumentation).
Ordnerstruktur von Maven
Ordnerstruktur von Maven

Die Konfigurationsdatei: Das Project Object Model - die pom.xml

Die zentrale Konfigurationsdatei für alle Maven-Projekte ist die pom.xml, in der das Project Object Model beschrieben ist.

Hier finden sich alle Angaben, die bei der Projekterzeugung vorgenommen wurden (z.B. ArtifactId: <artifactId>myFirstMavenProject</artifactId>), die zugehörige Java Version (<java.version>11</java.version>), weitere Projekteigenschaften (<properties>...</properties>), Abhängigkeiten (<dependencies>...</dependencies>) und Maven-Plugins (<build><plugins>...</plugins></build>). Bei großen Projekten werden die Dateien schnell unübersichtlich, um so wichtiger, sich mit der oben genannten Struktur vertraut zu machen (gekürzte Ausgabe der Projekt-pom.xml):

Diese XML-Datei entspricht den syntaktischen Regeln der Wohlgeformtheit (well formed XML: nur ein Root-Element, alle geöffneten Tags werden in identischer Reihenfolge wieder geschlossen usw). Außerdem stellt die pom.xml ein valides XML-Dokument dar, d.h. sie kann gegen die semantischen Regeln einer Schema-Datei validiert werden (valid XML: die Reihenfolge der Tags, Attribute, Inhalte entspricht den Festlegungen dieses Schemas http://maven.apache.org/xsd/maven-4.0.0.xsd).

In der pom.xml müssen immer mal Änderungen vorgenommen werden (Abhängigkeiten oder Plugins ergänzt usw.), daher ist es ratsam einen Editor zur komfortablen XML-Bearbeitung zur Hand zu haben (Plugins dafür haben eigentlich alle geläufigen Editoren).

Maven Lifecycle

Maven unterscheidet drei Haupttätigkeiten, die es als Lifecycle bezeichnet:

  • default: das eigentliche Erstellen und Veröffentlichen von Software
  • clean: Aufräumarbeiten, um nicht mehr benötigte Dateien des Buildprozesses zu löschen
  • site: erstellt eine Projektdokumentation als Website

Maven Phasen des Default-Lifecycles

Der Lifecycle default besteht aus einer ganzen Reihe von Phasen. Die wesentlichsten Phasen sind im folgenden UML-Aktivitätsdiagramm dargestellt:

Kurzübericht der Maven-Phasen
Kurzübericht der Maven-Phasen

Zwischen den oben abgedruckten Hauptphasen befinden sich noch weitere. Insgesamt sind es 23 Phasen, eine Übersicht findet sich z.B. in diesem Bild.

Mit dem Befehl

wird nicht nur die jeweilige Phase ausgeführt, sondern alle Phasen einschließlich der genannten. mvn test führt also auch validate und compile aus, mvn deploy führt sämtliche Phasen aus. Sofern der Befehl nicht in dem Ordner ausgeführt wird, in dem sich die pom.xml befindet, muss ein Pfad zur pom.xml mit Hilfe des Arguments -f übergeben werden (z.B.: mvn site -f .\myFirstMavenProject\pom.xml).

Das lässt sich mit dem oben erstellten Projekt ausprobieren: Das Beispielprojekt enthält unter ./src/main/java/com/example/test/HelloWorld.java eine ausführbare Datei, unter `./src/test/java/com/example/test/HelloWorldTest.java einen ausführbaren Test (ohne Testfunktionalität).

Wir können die einzelnen Phasen nacheinander manuell aufrufen:

  • mvn validate: Es passiert noch nicht viel. Da die Projektstruktur in Ordnung ist wird BUILD SUCCESS ausgegeben und die Phase beendet.

    [INFO] Scanning for projects...
    [INFO]
    [INFO] -----------------< de.csbme.ifaxx:myFirstMavenProject >-----------------
    [INFO] Building myFirstMavenProject 1.0-SNAPSHOT
    [INFO] --------------------------------[ jar ]---------------------------------
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  0.247 s
    [INFO] Finished at: 2022-10-26T08:15:10+02:00
    [INFO] ------------------------------------------------------------------------
  • mvn compile: Die Validierung wird ausgeführt, danach wird nach Klassen gesucht und diese kompiliert. Die dabei entstehenden Bytecode-Dateien (*.class) finden sich in den jetzt neu erzeugten Ordnern unter ./target/classes

    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ myFirstMavenProject ---
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] skip non existing resourceDirectory C:\Users\hanne\testpro\myFirstMavenProject\src\main\resources
    [INFO]
    [INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ myFirstMavenProject ---
    [INFO] Changes detected - recompiling the module!
    [INFO] Compiling 2 source files to C:\Users\hanne\testpro\myFirstMavenProject\target\classes
    [WARNING] system modules path not set in conjunction with -source 11
  • mvn test: Wie compile, danach werden jedoch auch noch die Tests kompiliert (Bytecode in ./target/test-classes) und ausgeführt. Die Testergebnisse werden in der Konsole ausgegeben:

    [INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ myFirstMavenProject ---
    [INFO]
    [INFO] -------------------------------------------------------
    [INFO]  T E S T S
    [INFO] -------------------------------------------------------
    [INFO] Running com.example.test.HelloWorldTest
    [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.034 s - in com.example.test.HelloWorldTest
    [INFO]
    [INFO] Results:
    [INFO]
    [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
  • mvn package: Wie test, jedoch werden die kompilierten Bytecodedateien in ein Archiv verpackt (z.B. ein ausführbares Java-Archiv JAR - das nutzen wir i.d.R. / ein WAR: Web Application Archive, z.B. für Tomcat-Server/ oder ein EAR für JavaEE Anwendungen für JBOSS oder WebSphere). Diese Datei stellt das Artefakt dar, das später veröffentlicht wird.

    [INFO] --- maven-jar-plugin:3.1.1:jar (default-jar) @ myFirstMavenProject ---
    [INFO] Building jar: C:\Users\hanne\testpro\myFirstMavenProject\target\myFirstMavenProject-1.0-SNAPSHOT.jar
  • mvn integration-test und mvn verify: Wenn diese Phasen konfiguriert sind, dann wird package ergänzt um die hinterlegten Integrationstests. Außerdem werden weitere Kontrollen durchgeführt (z.B. Codeabdeckung usw.), die sicherstellen sollen, dass sich das Artefakt in dem geforderten Zustand befindet.

  • mvn install: führt alle vorigen Phasen aus und installiert das Artefakt lokal im Maven-Repository. Damit ist es als Abhängigkeit für andere Projekte verfügbar.

    [INFO] --- maven-install-plugin:2.4:install (default-install) @ myFirstMavenProject ---
    [INFO] Installing C:\Users\hanne\testpro\myFirstMavenProject\target\myFirstMavenProject-1.0-SNAPSHOT.jar to C:\Users\hanne\.m2\repository\de\csbme\ifaxx\myFirstMavenProject\1.0-SNAPSHOT\myFirstMavenProject-1.0-SNAPSHOT.jar
    [INFO] Installing C:\Users\hanne\testpro\myFirstMavenProject\pom.xml to C:\Users\hanne\.m2\repository\de\csbme\ifaxx\myFirstMavenProject\1.0-SNAPSHOT\myFirstMavenProject-1.0-SNAPSHOT.pom
  • mvn deploy: Wenn diese Phase konfiguriert ist, wird das Artefakt in ein Remote-Repository für Artefakte übertragen. Da das in unserem Fall nicht konfiguriert ist, wirft diese Phase einen Fehler.

    [INFO] --- maven-deploy-plugin:2.7:deploy (default-deploy) @ myFirstMavenProject ---
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD FAILURE
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  7.266 s
    [INFO] Finished at: 2022-10-26T08:43:20+02:00
    [INFO] ------------------------------------------------------------------------
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy (default-deploy) on project myFirstMavenProject: Deployment failed: repository element was not specified in the POM inside distributionManagement element or in -DaltDeploymentRepository=id::layout::url parameter -> [Help 1]

Neben diesen Hauptphasen des Default-Lifecyles (sowie der zahllosen Unterphasen, die wir hier unterschlagen haben) gab es ja noch zwei weiter Lifecyles, die wir auch kurz ausprobieren wollen:

Ausführen eines mit Maven erstellten Projekts

In Maven selbst wird das Projekt nur erstellt, ausgeführt wird das jeweilige Artefakt abhängig vom Typ. JAR-Dateien können (nachdem sie mit mvn package gebaut wurden) i.d.R. direkt in der JVM gestartet werden über den Befehl:

Es gibt aber auch den Weg über das exec-Plugin. Dazu muss im Properties-Bereich die Starterklasse (die Klasse mit der public static void main()- Methode) angegeben werden:

<properties>...
    <exec.mainClass>com.example.test.HelloWorld</exec.mainClass>
...<properties>

Das Maven-Goal (das Plugin) ruft man dann wie folgt auf:

mvn exec:java

Da im vorhinein der Code kompiliert werden muss, erfolgt der Aufruf häufig über eine Verkettung mehrerer Lifecyle (clean/default) Phasen (compile) und Plugins/Goals.

mvn clean compile exec:java

Der Aufruf erfolgt bei ReST-Services und anderen Artefakten auf anderem Weg. Wir werden uns das zu gegebenem Zeitpunkt genauer ansehen.

Leitfragen

  • Was ist im Kontext von Maven ein Artefakt?

  • Was versteht man im Kontext von Maven unter einer Phase?

  • Was versteht man im Kontext von Maven unter einem Goal?

  • In welche wesentlichen Bereiche gliedert sich die pom.xml?

  • Wie hängen die Phasen in Maven zusammen?


Hinweis zur Nachnutzung als Open Educational Resource (OER)

Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: Maven installieren” von H. Stein (oer-informatik.de), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/build-tool-maven veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/java-advanced/build-tool-maven. Stand: 07.09.2023.

[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: