Maven und Continuous Integration

Modul #S2

Ziele

  • Ich kenne die Grundlagen von Maven.
  • Ich kann Maven lokal konfigurieren.
  • Ich kann im Artifactory Abhängigkeiten suchen und diese verwenden.
  • Ich kenne die Grundlagen von Project Object Models (POM).
  • Ich kenne die wichtigsten Maven Befehle und kann diese auf der Kommandozeile anwenden.
  • Ich kann die Abhängigkeiten meiner Applikationen mit Maven verwalten.
  • Ich kann Maven Plugins konfigurieren und damit meinen Maven-Build steuern.
  • Ich kann den Begriff Continuous Integration erklären.
  • Ich kenne die Komponenten der Deployment-Pipeline und deren Aufgaben.
  • (Optional): Ich habe erste Erfahrungen gesammelt mit dem alternativen Build-Tool Gradle.

Maven

Allgemeine Informationen

Apache Maven ist ein Build-Management Tool. Das heisst, Maven kann den Build eines Projekts von einer einzigen Datei aus steuern. Diese zentrale Datei ist das Project Object Model, kurz auch POM genannt. Ein Build ist der Prozess, bei dem der Quellcode eines Programms in eine ausführbare Form gebracht wird, häufig durch Kompilieren und Paketieren. Der Build eines Projekts kann dabei von einfacher Kompilierung bis zur Auslieferung einer Anwendung auf eine bestimmte Plattform reichen.

Damit Maven funktionieren kann, benötigt ein Projekt die folgenden Dinge:

  • Eine Maven-Installation, entweder separat oder Built-In wie beispielsweise mit IntelliJ
  • Eine Project Object Model Datei pro Projekt oder Modul (es handelt sich um eine XML-Datei)
  • Ein zentrales Maven-Repository
  • Ein lokales Maven-Repository
  • Eine Konfigurationsdatei mit dem Namen settings.xml

Manuelle Installation

Idealerweise wurde Apache Maven bereits mit IntelliJ installiert. Damit du Maven auch auf der Kommandozeile ausführen kannst, kannst du Maven hier herunterladen: https://maven.apache.org/download.cgi. Verwende die Binary anstelle der Source, und zwar am besten die Datei im Binary zip archive Format.

Klicke dazu auf den folgenden Link, wie hier im Beispiel: Apache Maven Project Download (Stand: 22.09.2024)

Nachdem du die Datei heruntergeladen hast, kannst du den folgenden Ordner erstellen:
C:\Program Files\Apache\Maven\.

Entpacke die heruntergeladene Datei dort. Du kannst danach die Umgebungsvariablen auf dieses Verzeichnis setzen.


Umgebungsvariablen setzen

Damit Maven auch auf der Command-Line funktioniert, muss eine Umgebungsvariable gesetzt werden. Unter Windows muss also der Pfad zu deiner installierten Maven-Version hinzugefügt werden. Dadurch weiss Windows, wo die Binary für Maven zu finden ist, wenn du Maven aus dem Terminal ausführst. Die folgenden Schritte sind dazu notwendig:

#Beschreibung
1Anwendung “Systemumgebungsvariablen bearbeiten” aus der Systemsteuerung starten. Falls das nicht geht, musst du dir (temporär) lokale Admin-Rechte aktivieren.
2Unten rechts auf den Button “Umgebungsvariablen” klicken.
3Im unteren Teil “Benutzervariablen” die Variable “Path” suchen und anklicken.
4Auf den Button “Bearbeiten…” klicken.
5Oben rechts auf den Button “Neu” klicken, es erscheint eine neue Zeile ganz unten.
6Den Pfad zu deinem installierten Maven einfügen. Hier kannst du das erstellte Verzeichnis verwenden. Der Pfad sollte auf bin zeigen, also zum Beispiel: C:\Program Files\Apache\Maven\apache-maven-3.9.9\bin. Du musst sicherstellen, dass die Version mit deiner heruntergeladenen Version übereinstimmt.
7Alle offenen Windows-Fenster mit “OK” schliessen.

Um die Installation zu überprüfen, führen den folgenden Befehl in deinem Terminal (du findest es unter Eingabeaufforderung oder cmd in der Windows Suche) aus:
mvn -version

Falls es korrekt installiert ist, wird dir Maven die Version liefern, also zum Beispiel:
Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae)

img.png

Die Version muss nicht mit deiner übereinstimmen.


IntelliJ IDEA einrichten

Im IntelliJ findet man in den allgemeinen Einstellungen auch die Einstellungen für Maven. Normalerweise sind diese Einstellungen bereits korrekt.

Intellij Maven settings

Die wichtigsten Einstellungen sind:

EinstellungBeschreibung
Maven home directoryZeigt auf das Verzeichnis einer Maven-Installation. Das IntelliJ verfügt bereits über eine Maven-Installation, diese wird als “Bundled” bezeichnet.
User settings fileDie XML-Datei, welche bei der Installation angelegt wurde.
Local repositoryDer Ablageort für das lokale Repository, dieser ist normalerweise unter C:\Users\<Personalnummer>\.m2.\repository zu finden.

Bei diesen Einstellungen muss überprüft werden, dass die Pfad-Angaben für die XML-Datei und das lokale Repository korrekt sind.


pom.xml

Der Aufbau eines Project Object Models kann grob in folgende Abschnitte unterteilt werden, hier erklärt an einem umfangreichen Beispiel. Die einzelnen Teile werden gleich im Anschluss näher erläutert. Bitte beachte, dass dieses Project Object Model nicht alle Inhalte vollständig erklärt, sondern nur als erstes Beispiel dient.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<!-- (1) Header -->
<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>

    <!-- (2) Angaben zum Artefakt -->
    <groupId>ch.sbb.interviewtool</groupId>
    <artifactId>interviewtool-backend</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <!-- (3) Angaben zum Parent-Projekt -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.4.RELEASE</version>
        <relativePath/>
    </parent>

    <!-- (4) Properties -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.21</java.version>
        <maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
        <timestamp>${maven.build.timestamp}</timestamp>
    </properties>

    <!-- (5) Abhängigkeiten -->
    <dependencies>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.6</version>
        </dependency>

        <!-- Unit- und Integrationstests -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- (6) Build-Informationen -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <compilerVersion>1.21</compilerVersion>
                    <source>1.21</source>
                    <target>1.21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <!-- (7) Entwickler-Informationen -->
    <developers>
        <developer>
            <id>U000000</id>
            <name>Vorname Name</name>
            <email>vorname.name@sbb.ch</email>
            <organization>SBB</organization>
            <organizationUrl>https://www.sbb.ch</organizationUrl>
            <roles>
                <role>Software Architect</role>
                <role>Lead Developer</role>
            </roles>
        </developer>
    </developers>
</project>

Abschnitt 1

Der Header einer Project Object Model Datei bleibt grundsätzlich so wie dargestellt. Die Angaben zum Schema sind dabei optional. Falls andere Schemas verwendet werden, so sind diese hier zu deklarieren.

Abschnitt 2

Die Angaben zum Artefakt enthalten die folgenden Informationen:

  • Gruppen-ID: Die Gruppen-ID ist in Maven normalerweise als umgekehrte Domain-Name-Notation (Reverse Domain Name Notation) aufgebaut, ähnlich wie bei Java-Paketen. Diese Struktur dient dazu, Konflikte zwischen Artefakten von verschiedenen Organisationen zu vermeiden. Zum Beispiel wird die Gruppen-ID für ein Projekt der SBB oft in der Form ch.sbb beginnen, da sbb.ch die Domain der Schweizerischen Bundesbahnen ist. Beispiel: ch.sbb.interviewtool
  • Artefakt-ID: Die Artefakt-ID ist der eindeutige Name eines Projekts oder einer Komponente, der zusammen mit der Gruppen-ID und der Version verwendet wird, um ein Artefakt im Repository eindeutig zu identifizieren. Beispiel: interviewtool-backend, mit der Gruppen-ID: ch.sbb.interviewtool:interviewtool-backend.
  • Version: Die momentane Version des Projekts, diese wird später durch Releases verändert.
  • Paketierung: Angabe, in welcher Form das Artefakt geliefert wird. Der Default ist Java Archive (JAR).

Bei der Versionierung nutzt Maven die folgenden Standards:

  • Major-Version
  • Minor-Version
  • Incremental-Version
  • Build-Number
  • Qualifier

Dazu ein paar Beispiele:

TypBeispiel
Major-Version1.2.1
Minor-Version2.0
Incremental-Version1.2-SNAPSHOT
Patch1.2.1
Build-Number1.4.2-12
Qualifier1.2-beta-2

Alle Versionen mit Qualifier sind dabei älter als die gleiche Version ohne Qualifier. Beispielsweise ist die Version 1.2-beta-2 älter als die Version 1.2. Gleiche Versionen mit unterschiedlichen Qualifiern werden durch den Vergleich dieser als String verglichen. So ist die Version 1.2-beta-2 neuer als die Version 1.2-alpha-6.

Der SNAPSHOT-Qualifier wird verwendet, wenn eine Version noch nicht ausgeliefert wurde. So wird die Version 0.1.2-SNAPSHOT sehr wahrscheinlich als Version 0.1.2 ausgeliefert werden.

Abschnitt 3

Falls das Projekt Bestandteil eines anderen Projektes ist, müssen hier die Artefakt-Angaben des sogenannten Parent-Projekts hinterlegt werden. Dies ist vor allem bei Spring-Boot Projekten wichtig.

Abschnitt 4

Die Einstellungen in Maven sind beliebig wählbare Tags. So kann beispielsweise eine bestimmte Einstellung oder eine Version definiert werden.

Beispiel:

1
<special.setting>Value</special.setting>

Innerhalb der Project Object Model Datei kann dann mit

1
${special.setting}

auf die Einstellung (Tag) und damit auf dessen Wert (Value) zugegriffen werden.

Abschnitt 5

Abhängigkeiten zu Fremdbibliotheken. Diese sollten stets Gruppen-ID, Artefakt-ID und Version enthalten. Der Typ der Abhängigkeit gibt an, um welche Art von Bibliothek es sich handelt. Nicht alle Java-Bibliotheken werden als JAR ausgeliefert. Eine Liste der möglichen Typen findest du hier: https://maven.apache.org/ref/3.6.3/maven-core/artifact-handlers.html. Vielfach wird auch der Scope verwendet, der angibt, in welchem Umfang die Fremdbibliothek einbezogen wird. Mögliche Scopes sind unter anderem:

  • compile - Das ist der Default-Scope. Diese Bibliotheken sind in allen Klassenpfaden verfügbar (Classpath), werden also mitausgeliefert.
  • provided - Gleich wie compile, ausser das die Bibliothek zur Laufzeit von einem Container (wie dem JDK) erwartet und bereitgestellt wird.
  • runtime - Zeigt an, dass die Bibliothek zur Kompilierung nicht verwendet wird. Zur Laufzeit steht sie dann zur Verfügung.
  • test - Die Bibliothek steht nur für Tests zur Verfügung und wird nur fürs Testing benötigt.
  • system - Gleich wie provided, mit der Ausnahme, dass die Bibliothek explizit auf dem System zur Verfügung stehen muss.

Abschnitt 6

Die Build-Informationen konfigurieren den Ablauf des Maven-Builds. Mit Plugins kann der Build selbst durch spezifische Erweiterungen beliebig angepasst werden. Es ist auch möglich, eigene Maven-Plugins zu entwickeln. Es stehen sehr viele Plugins für Maven zur Verfügung, eine Übersicht gibt es hier.

Abschnitt 7

Die Entwickler-Informationen dienen dazu, an der Entwicklung beteiligte Personen zu identifizieren.


Beispiel einer Abhängigkeit (spring-boot-starter)

Die Dependency spring-boot-starter ist eine grundlegende Bibliothek für Spring-Boot Projekte, die automatisch alle benötigten Abhängigkeiten einbindet, um die Anwendung zu starten und auszuführen. Dadurch wird der Aufbau von Spring-Anwendungen vereinfacht, da häufig verwendete Bibliotheken in einem einzigen Package zusammengefasst sind.

Ein weiteres Beispiel für eine Abhängigkeit ist Lombok. Diese Library wird in einem eigenen Kapitel ausführlich beschrieben.

Commands

Maven lässt sich auf der Kommandozeile oder im IntelliJ-Terminal ausführen. Damit wir sehen, ob das wirklich klappt, kannst du das Terminal öffnen und den folgenden Befehl eingeben:

1
mvn -version

Das sollte nun in etwa so aussehen:

Maven Lifecycle

Bevor wir die einzelnen Befehle kurz anschauen, werfen wir einen Blick auf die einzelnen Phasen des Maven-Lebenszyklus.

Jeder in der Grafik genannte Befehl wird zusätzlich die vorangehenden Phasen ausführen. Die Ausführung des Befehls mvn package führt somit die Phasen validate, compile, test und package aus.

help

1
mvn -help

Das Ergebnis dürfte klar sein. Maven listet alle möglichen Befehle auf.

dependency:tree

1
mvn dependency:tree

Dieser Befehl listet alle Abhängigkeiten zu Fremdbibliotheken als Baum auf. Das ist grundsätzlich sehr praktisch, wenn man doppelte Abhängigkeiten erkennen oder vermeiden will.

clean

1
mvn clean

Dieser Befehl löscht alle vorherigen lokalen Maven-Build-Artefakte, indem er das Verzeichnis ’target’ entfernt.

compile

1
mvn compile

Kompiliert den Sourcecode je nach Abhängigkeit von Plugins. Wenn also beispielsweise ein Maven-Compiler-Plugin verwendet wird, so wird dieses als Regelwerk für die Kompilierung herangezogen.

test

1
mvn test

Führt alle Tests aus. In einem Java-Projekt sind dies beispielsweise alle Unit-Tests mit JUnit.

package

1
mvn package

Führt einen lokalen Maven-Build aus, startet alle Tests und paketiert die Anwendung (normalerweise als JAR) in das Verzeichnis “target”.

verify

1
mvn verify

Prüft die Testergebnisse aller ausgeführten Integrationstests, normalerweise wird das Maven-Failsafe-Plugin für diesen Maven-Befehl vorausgesetzt.

install

1
mvn install

Lädt das Artefakt in dein lokales Maven-Repository (dies findest du typischerweise unter %UserProfile%.m2).

skip tests

1
mvn install -DskipTests

Mit dem Parameter -DskipTests kannst du die Ausführung der Tests während der Installation überspringen, um Zeit zu sparen. Der Parameter kann auch bei anderen Aktionen wie compile, package usw. verwendet werden.

deploy

1
mvn deploy

Lädt das Artefakt in das Remote-Repository (Artifactory) hoch.

Die Maven-Befehle lassen sich kombinieren. Sehr nützlich ist zum Beispiel:

1
mvn clean install

Selbstverständlich gibt es sehr viele zusätzliche Optionen für die einzelnen Maven-Befehle.


task1 Jetzt bist du dran. Löse bitte die Aufgaben in den Labs.


hint-gradle (Optional) Gradle: Als Alternative zu Maven wird oft auch das Build-System Gradle eingesetzt. Unter Building Java Applications Sample kannst du dir einen ersten Eindruck verschaffen.

Last modified October 11, 2024: Formatted markdown files (4b3a076f6)