Maven und Abhängigkeiten
Das Problem: Software besteht nicht nur aus eigenem Code
Dein Webservice soll HTTP sprechen, JSON lesen, mit einer Datenbank reden und einen Webserver starten. Nichts davon schreibst du selbst — das haben andere schon gebaut und als Bibliothek veröffentlicht.
Ohne Hilfsmittel müsstest du:
- jede Bibliothek als
.jar-Datei von irgendeiner Website herunterladen, - sie in einen Ordner legen und dem Compiler bekannt machen,
- herausfinden, welche weiteren Bibliotheken sie ihrerseits braucht,
- das alles bei jedem Update wiederholen,
- und sicherstellen, dass jeder im Team exakt dieselben Versionen hat.
Spätestens bei Schritt 3 wird es unübersichtlich. Genau dafür gibt es Maven.
Ein Build-Werkzeug. Es beschafft die benötigten Bibliotheken, übersetzt den Quelltext, führt die Tests aus und packt am Ende ein auslieferbares Programm.
Die Beschreibung des Projekts steht in einer einzigen Datei: der pom.xml.
Die pom.xml
POM steht für Project Object Model. Die Datei beschreibt vor allem, was das Projekt ist und was es braucht. Wie gebaut wird, muss man dagegen selten aufschreiben: Maven bringt dafür einen Standardablauf mit. (Wo es nötig ist, lässt er sich in der pom.xml anpassen — im Gästebuch-Projekt steht so ein Eintrag für Lombok.)
<project>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.1</version>
</parent>
<groupId>de.szut</groupId>
<artifactId>personenverwaltung</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>25</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
</dependencies>
</project>
Die Adresse einer Bibliothek
Jede Bibliothek der Welt ist über drei Angaben eindeutig bestimmt — man nennt sie GAV-Koordinaten:
| Angabe | Bedeutung | Beispiel |
|---|---|---|
| GroupId | Wer hat es gebaut? Meist eine umgekehrte Domain | org.springframework.boot |
| ArtifactId | Wie heißt das Bauteil? | spring-boot-starter-webmvc |
| Version | Welcher Stand? | 4.1.1 |
Dein eigenes Projekt hat ebenfalls solche Koordinaten — de.szut / personenverwaltung / 0.0.1-SNAPSHOT. Genau die hast du im Spring Initializr eingetragen.
SNAPSHOT?Der Zusatz kennzeichnet eine Version in Entwicklung, die sich noch ändern darf. Eine Version ohne diesen Zusatz gilt als fertig und wird nie wieder verändert.
Woher die Bibliotheken kommen
Maven lädt sie aus einem Repository — einem öffentlichen Archiv im Internet. Der Standard heißt Maven Central und enthält Millionen von Bibliotheken.
Dir begegnet Repository in diesem Kurs zweimal, und die beiden haben nichts miteinander zu tun:
| Was es ist | |
|---|---|
| Maven-Repository | Ein Archiv mit .jar-Dateien — hier auf dieser Seite gemeint |
| Spring-Data-Repository | Ein Java-Interface für den Datenbankzugriff, etwa PersonRepository |
Wer aus dem ersten Lehrjahr DAO kennt: Das Spring-Data-Repository ist dasselbe Konzept. Mit Maven hat es nichts zu tun.
Heruntergeladene Bibliotheken landen im lokalen Repository auf deinem Rechner (C:\Users\<name>\.m2\repository). Deshalb dauert der erste Projektstart lange und jeder weitere nur noch Sekunden — beim zweiten Mal ist alles schon da.
Transitive Abhängigkeiten
Das ist der eigentliche Gewinn. Eine Bibliothek braucht selbst wieder Bibliotheken, und die wieder andere. Maven verfolgt diese Kette automatisch.
Ein Blick in dein eigenes Projekt macht das greifbar:
spring-boot-starter-webmvc
├── spring-boot-starter-jackson
│ └── spring-boot-jackson
│ └── jackson-databind ← wandelt JSON in Objekte um
│ ├── jackson-annotations
│ └── jackson-core
└── spring-boot-starter-tomcat
└── tomcat-embed-core ← der eingebaute Webserver
In deiner pom.xml stehen 8 Abhängigkeiten. Tatsächlich lädt Maven 123 JAR-Dateien — alles Weitere sind transitive Abhängigkeiten.
Das kannst du selbst nachsehen:
./mvnw dependency:tree
Genau deshalb hast du Jackson nie eingebunden, obwohl deine Anwendung JSON verarbeitet: Es kommt über spring-boot-starter-webmvc mit.
Starter: fertig geschnürte Bündel
Bibliotheken, deren Name mit spring-boot-starter- beginnt, enthalten selbst fast keinen Code. Sie sind Bündel, die eine sinnvolle Kombination anderer Bibliotheken zusammenfassen.
| Starter | Bringt mit |
|---|---|
spring-boot-starter-webmvc | Spring MVC, Tomcat, Jackson |
spring-boot-starter-data-jpa | Spring Data JPA, Hibernate, Verbindungspool |
spring-boot-starter-actuator | Überwachungs-Endpunkte |
Der Vorteil: Du triffst eine Entscheidung („ich baue eine Web-Anwendung") statt fünfzehn.
Warum bei den meisten Abhängigkeiten keine Version steht
Ist dir aufgefallen, dass in der pom.xml fast überall die <version> fehlt? Das liegt am <parent>-Eintrag:
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.1</version>
</parent>
Dieser Eltern-POM enthält eine große, geprüfte Liste: Zu Spring Boot 4.1.1 gehört Spring Framework 7.0.9, Jackson 3.1.5, Tomcat 11.0.24 und so weiter. Alle diese Versionen sind aufeinander abgestimmt.
Du kannst eine Version angeben und damit die Vorgabe überstimmen. Tu es nur, wenn du einen guten Grund hast — du verlässt damit die geprüfte Kombination und kannst schwer auffindbare Fehler erzeugen.
Der Maven Wrapper
Im Projekt liegen zwei Dateien, die du nicht selbst angelegt hast: mvnw (Linux/macOS) und mvnw.cmd (Windows). Das ist der Maven Wrapper.
Er lädt beim ersten Aufruf genau die Maven-Version herunter, die zum Projekt gehört, und benutzt diese. Ergebnis: Alle bauen mit derselben Version — unabhängig davon, was auf dem einzelnen Rechner installiert ist. Auf manchen Rechnern muss Maven gar nicht erst installiert sein.
mvnw.cmd clean verify
Nutze den Wrapper, nicht dein lokales Maven. Er ist der Grund, warum ein Projekt auf dem Rechner der Kollegin genauso baut wie auf deinem und wie auf dem Build-Server.
Die wichtigsten Befehle
Maven arbeitet in Phasen, die aufeinander aufbauen. Ruft man eine Phase auf, laufen alle vorherigen mit.
| Befehl | Was passiert |
|---|---|
mvnw clean | löscht den Ordner target mit allen Bauergebnissen |
mvnw compile | übersetzt den Quelltext nach target/classes |
mvnw test | compile + führt die Tests aus |
mvnw package | test + packt eine .jar-Datei |
mvnw verify | package + zusätzliche Prüfungen |
mvnw spring-boot:run | startet die Anwendung direkt |
clean ist kein Allheilmittel, aber oft die LösungWenn sich der Build merkwürdig verhält, obwohl der Code richtig aussieht, liegen häufig alte Bauergebnisse im target-Ordner. mvnw clean verify baut alles von Grund auf neu.
Wo die Abhängigkeiten im Projekt landen
| Ordner | Inhalt | In die Versionsverwaltung? |
|---|---|---|
src/ | dein Quelltext | ja |
pom.xml | die Projektbeschreibung | ja |
mvnw, .mvn/ | der Wrapper | ja |
target/ | Bauergebnisse, erzeugte .jar | nein |
.m2/repository | heruntergeladene Bibliotheken | liegt außerhalb des Projekts |
Bibliotheken werden also nie ins Projekt kopiert. Weitergegeben wird nur die pom.xml — der Rest lässt sich daraus jederzeit wiederherstellen.
- Maven beschafft Bibliotheken, übersetzt, testet und paketiert. Beschrieben wird das Projekt in der
pom.xml. - Jede Bibliothek hat GAV-Koordinaten: GroupId, ArtifactId, Version.
- Bibliotheken kommen aus Maven Central und liegen danach im lokalen Repository.
- Transitive Abhängigkeiten zieht Maven automatisch mit — aus 8 Einträgen werden 123 JAR-Dateien.
- Starter sind Bündel; die
<parent>-Angabe legt die abgestimmten Versionen fest. - Der Wrapper (
mvnw) sorgt dafür, dass alle mit derselben Maven-Version bauen. - Bibliotheken landen nie im Projektordner — weitergegeben wird die
pom.xml.
Weiterlesen
- Werkzeuge in IntelliJ — dasselbe zum Anklicken, plus das Maven-Fenster
- Automatisiert testen — die Test-Abhängigkeiten und ihr Geltungsbereich
- Docker und Container — dieselbe Grundfrage eine Ebene höher