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.

Maven

Allgemeine Informationen

Apache Maven ist ein Build-Management Tool. Von einer einzelnen Datei aus kann Maven den Build eines Projektes steuern. Diese zentrale Datei ist das Project Object Model, kurz auch POM genannt. Der Build eines Projektes 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

Installation

Die Installation von Apache Maven wurde idealerweise bereits durchgeführt. Falls nicht, kann Maven hier heruntergeladen werden: https://maven.apache.org/download.cgi, beim Herunterladen das Binary auswählen (nicht die Source).


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 erklären kann, es dient nur als erstes Beispiel.

 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: Normalerweise eine umgekehrte URL, also beispielsweise ch.sbb.interviewtool. Darin sollte der Projektname enthalten sein.
  • Artefakt-ID: Der Name des Projekts oder der Komponente.
  • 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. Mögliche Typen sind hier zu finden: https://maven.apache.org/ref/3.6.3/maven-core/artifact-handlers.html. Vielfach wird auch noch der Scope verwendet. Er gibt an in welchem Umfang die Fremdbibliothek miteinbezogen wird. Mögliche Scopes sind:

  • 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.


IntelliJ IDEA einrichten

Im IntelliJ findet man in den allgemeinen Einstellungen auch die Einstellungen für Maven.

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.


Umgebungsvariable aufsetzen

Damit Maven auch auf der Command-Line funktioniert, muss eine Umgebungsvariable gesetzt werden. Im Windows muss also der Pfad zur Built-In Version des IntelliJ hinterlegt werden. 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 “Systemvariablen” 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 zum Built-In Maven einfügen. Dieser ist normalerweise “<Installationsort IntelliJ IDEA>\plugins\maven\lib\maven3\bin”
7Alle offenen Windows-Fenster mit “OK” schliessen.

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. Dies vereinfacht den Aufbau von Spring-Anwendungen, indem häufig verwendete Bibliotheken in einem einzigen Package zusammengefasst werden.

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, könnt ihr 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 Befehle ausführen. Die Ausführung von “mvn package” wird also die Phasen validate, compile, test und package ausführen.

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/vermeiden will.

clean

1
mvn clean

Dieser Befehl löscht alle vorherigen lokale Maven-Build-Artefakte, indem er das Verzeichnis “target” löscht.

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

“Installiert” das Artefakt im lokalen Maven-Repository.

skip tests

1
mvn install -DskipTests

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

deploy

1
mvn deploy

“Installiert” das Artefakt im Remote-Repository (Artifactory).

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.