To main content

JavaLand 2026 Rückblick: Drei praktische Maven-Ideen, die du sofort ausprobieren kannst

Veröffentlicht von Benjamin Marwell am

JavaLand 2026 schloß am Mittwoch, den 11. März ihre Pforten für die Vorträge und Aussteller, und Maarten Mulders und ich hatten viel Spaß mit unserem Talk »Accelerating Maven Builds«. Wir haben praktische Tipps und Tricks zum Thema »wie messe ich meinen Build« und wie beschleunige ich meinen Maven-Build geteilt. Von den Fragen aus dem Publium haben wir geschlossen, dass es viel Interesse an diesem Thema gibt.

Dieser Rückblick konzentriert sich auf die Maven-Performance, mvnd, die Apache Maven Build Cache Extension sowie Reactor-Builds. Außerdem beantworten wir einige der am häufigsten gestellten Fragen aus dem Publikum.

1. Änderungen am Talk für die JavaLand 2026

Auf der JavaLand 2026 hatten wir nur einen kürzeren Slot von 40 Minuten. Daher haben wir unseren Talk ein klein wenig eingekürzt. Zum einen haben wir die Begriffs-Folie entfernt, doppelte Schlussfolgerungen (Pro/Contra und Fazit) entfernt. In der Live-Präsentation habe ich dann auch die Folien zu JUnit 4 und TestNG übersprungen, da niemand im Publikum diese Test-Frameworks noch verwendet.

2. Drei Tipps, um deinen Maven-Build sofort zu beschleunigen

2.1. Nutze Apache mvnd anstatt mvn

Probiere mvnd (Maven Daemon) aus, ein Drop-In-Ersatz für mvn. mvnd hält eine JVM im Hintergrund »warm« und behält daher auch etliche Klassen (z.B. von Plugins) im Speicher. Das Haupt-Feature ist aber der parallele Build von mehreren Modulen Deines Reactor-Projektes gleichzeitig.

Falls Du Warnungen siehst, dass einige Plugins nicht threadsafe seien, prüfe zuerst, ob es Updates für diese Plugins gibt. Falls es wider Erwarten keine Updates für die betroffenen Plugins gibt, solltest Du vielleicht ein Issue bei den Plugin-Maintainern öffnen, da diese Plugins thread-safe sein sollten, um mit mvnd oder mvn -T1C zu arbeiten.

Falls alles fehlschlägt, kannst Du versuchen, die Warnungen zu ignorieren — wenn es funktioniert, funktioniert es. Es ist letztlich nur ein Flag, welches aktiv vom Plugin-Maintainer gesetzt werden muss. Ansonsten kannst Du auch auf ein anderes Plugin mit ähnlicher Funktionalität umsteigen, wenn alle Stricke reißen.

Möchtest Du tiefer in die Materie eintauchen, schau Dir gerne meinen Artikel Feed the Daemon: Faster Builds with Maven Reactor Modules an.

2.2. Ein neues Apache Maven Module/Subproject für neue Funktionalität erstellen

Das war DAS Thema: »Füttere den Maven Daemon«: Falls Du einen neuen Service oder eine neue Funktionalität zu Deiner Anwendung hinzufügen möchtest, erstelle ein neues Maven-Modul. Auf diese Weise erstellst Du »Futter« für den Maven Daemon, da die Abhängigkeiten zwischen den Modulen immer weniger und weniger linear werden. Sequentielle Builds können dann in parallel kompilier- und testbare Module aufgebrochen werden - je mehr Module das Projekt hat, desto besser.

2.3. Probiere die Apache Maven Build Cache Extension aus

Die Apache Maven Build Cache Extension ist eine noch relativ neue Erweiterung, die es Dir erlaubt, Build-Artefakte und Abhängigkeiten Deiner Module zu cachen.

Stell Dir vor, du hast ein Reactor-Projekt mit 5 sequentiellen Modulen, und du änderst etwas in Modul 5. Warum solltest du alles von Modul 1 bis 5 neu bauen, wenn du nur Modul 5 neu bauen musst? Die Build Cache Extension ermöglicht es dir, die Build-Artefakte von Modul 1 bis 4 zu wiederzuverwenden. Verwendest du zusätzlich einen Remote Cache, kannst du sogar einen Build Cache nutzen, der auf einer anderen Maschine erstellt wurde, z.B. in einer CI-Umgebung oder von einem Kollegen.

Bitte teile deine Erfahrungen und Ergebnisse deiner Experimente mit der Apache Maven Build Cache Erweiterung auf der Apache Maven User Mailing Liste.

3. Fragen aus dem Publikum

Wie so oft hatten wir wieder etliche gute Fragen aus dem Publikum. Hier sind einige Antworten zu den am häufigsten gestellten Fragen (und diejenigen, die wir interessant fanden).

3.1. Q: Warum sollte ich meine Software-Architektur für einen schnelleren Build ändern?

A: Wir empfehlen Dir nicht, die Architektur Deines Builds nur wegen der Geschwindigkeit des Builds zu ändern. Allerdings bringt Dir diese Änderung nicht nur Vorteile um der Geschwindigkeit Willen, sondern geht meistens auch mit einer besseren Architektur einher. Das hängt aber wirklich im Einzelfall vom Projekt bzw. Build ab.

Falls Du eine kleine Anwendung pflegst, kann das auseinanderreißen in einzelne Module die Arbeit nicht wert sein. Vermutlich dürfte es die Build-Zeit eh nicht wesentlich beeinflussen.

Pflegst du andererseits eine größere Anwendung, dann kann die Modularisierung die Build-Zeit und halt auch die Wartbarkeit deutlich positiv beeinflussen. Durch das auseinandernehmen der Anwendung in kleinere, fokussiertere Module kannst du vermeiden, dass Du in einem Modul Klassen aus einem anderen Modul nutzt, die Du hier nicht nutzen solltest. Legt man für einen einzelnen Service ein eigenes Modul an, führt das auch zum »separation of concerns« (wörtlich: »Trennung der Belange«), und das ist ein Prinzip eines guten Software-Designs.

Der Seiteneffekt ist das, was wir vorgestellt haben: Mehrere Module können parallel gebaut werden.

3.2. Q: Wie viel kann die Apache Maven Build Cache Erweiterung überspringen, wenn ein Change in einem »mittleren« Modul stattfand?

A: Die Antwort auf diese Frage hängt deutlich vom Reactor-Projekt ab.

3.2.1. Sequentielle Builds und flache Abhängigkeits-Graphen

Einfches Projekt mit 5 sequentiellen Modulen
Figure 1. Einfches Projekt mit 5 sequentiellen Modulen, Änderung in Modul 3

In einem einfachen, sequentiellen Build (mit mvn oder flachen Abhängigkeits-Graph): Der Build-Cach wird hier z.B. die ersten beiden Module überspringen, dann den Rest ab dem geänderten Modul kompilieren und testen — da alle weiteren Module von diesem abhängen.

3.2.2. Komplexe Multi-Module (Reactor) Builds

Beispiel eines komplexen Modul-Graphen; zeigt welche Geschwister-Module und abhängige Module einen Rebuild brauchen
Figure 2. Beispiel eines komplexen Modul-Graphen

Im obrigen Beispiel schaue Dir mal die Abhängigkeit zwischen /web/rest und /domain/service1 an. Es ist eine Laufzeit-Abhängigkeit. Falls du irgendetwas in /domain/service1 änderst, wird der Build-Cache fast alle anderen Module überspringen, inkl. /domain/api und alle /common-Module, aber wird natürlich /domain/service1 und /web/rest erneut kompilieren, da dieses Abhängigkeiten besitzen.

Hast du noch ein neues Modul /domain/service2 hinzu, wird dieses ebenfalls übersprungen.

4. Überraschende Erkenntnisse aus unserem Talk

4.1. Kaum noch JUnit 4 oder TestNG in Nutzung

Wir waren positiv überrascht, dass niemand aus dem Publikum noch JUnit 4, TestNG or Spock verwendet hat. Wir hatten erwartet, dass zumindest wenige Benutzer noch diese Test-Frameworks nutzen. Aber scheinbar haben schon alle auf JUnit Jupiter migriert. Wow! Bravo!

4.2. Nicht jeder kennt den Apache Maven Wrapper

Falls du mvnd nicht in deiner Continuous Integration-Umgebung nutzen kannst, denken erstaunlich wenige an die Nutzung von Apache Maven Wrapper, und wussten teilweise gar nicht, dass dieser existiert.

Besonders in Projekten, wo Du als Maintainer keine Kontrolle über Notebooks hast, ist ein »blessed« Build wichtig. Hierfür kann man via des Apache Maven Wrappers eine Apache Maven-Version »soft-forcieren«. Auch Entwicklungsumgebungen erkennen und empfehlen die Nutzung des Wrappers. Dieser wird dann üblicherweise auch in der Integrations-Umgebung verwendet, wenn Du deine Workflows oder Jenkinsfiles so konfigurierst, dass sie bash ./mvnw anstatt mvn ausführen.

Der große Vorteil dieses Ansatzes: Alle Entwickler und CI-Umgebungen verwenden die gleiche Version von Apache Maven, was dazu beitragen kann, Build-Probleme zu vermeiden, die durch unterschiedliche Maven-Versionen verursacht werden.

4.3. Nicht jeder kennt und/oder nutzt das Apache maven-enforcer-plugin

Eine weitere Sache, die uns ein bißchen überrascht hat, war die Tatsache, dass viele Leute das Apache Maven Enforcer Plugin nicht kannten oder zumindest nicht nutzten. Falls Du es nicht kennst kann ich nur empfehlen, es dir mal anzuschauen.

Was es kurz gesagt macht: Beim Start des Builds (in der ersten Phase) führt es eine Reihe von einfachen, in XML definierten Regeln aus um zu prüfen, ob die Build-Umgebung bestimmte Bedingungen erfüllt. Das kann etwa die Mindest-Version von Apache Maven sein, die Java-Version, das Betriebssystem, das Vorhandensein einer bestimmten Datei oder aber auch das Fehlen von bestimmten Abhängigkeiten.

4.4. Apache Maven Enforcer: Eingebaute Regeln

  • requireMavenVersion: Forciert eine bestimmte (Mindest-)Version von Apache Maven, die für den Build verwendet wird.

  • requireJavaVersion: Forciert eine bestimmte Java-Version, die für den Build verwendet wird.

  • bannedDependencies: Verbannt bestimmte Dependencies aus dem Build.

4.5. Mojohaus Extra Enforcer Regeln für das Apache Maven Enforcer Plugin

Ein paar interessante Mojohaus Extra Enforcer Regeln sind:

  • banDuplicateClasses: Verbannt duplizierte Klassen (z.B. aus mehreren Dependencies), damit es keine Klassenpfad-Fehler im Build gibt.

  • enforceBytecodeVersion: Forciert eine bestimmte Version des Bytecodes der kompilierten Klassen.

  • requireEncoding: Welcher Zeichensatz für die Quelldateien verwendet werden soll. Damit vermeidet man eine weitere Fehlerklasse durch mehrere Entwickler mit Windows vs Linux/Mac.

  • banCircularDependencies: Verbannt zirkuläre Abhängigkeiten zwischen Modulen. Auch damit steigt die Wartbarkeit.

5. Weiterführende Ressourcen

Das war es!

Versucht mvnd erst einmal lokal zu nutzen und vergleiche es mit dem Build mit mvn. Lass mich gerne in den Kommentaren wissen, ob sich deine Build-Performance hierdurch verändert hat.

5.1. Verwandte Blog-Beiträge