Enterprise Maven POM Beispielbuch
Ziel: Dieses Markdown-Buch zeigt mehrere fiktive, aber realistische Enterprise-Maven-Projekte.
Es ist für Lernen, Dokumentation, Workshops und als Vorlage für eigene Projekte gedacht.
Stand: 2026-07-02
Hinweis: Die verwendeten Versionen sind Beispielwerte. In echten Unternehmensprojekten sollten sie mit eurer Plattform-, Security- und Architekturvorgabe abgeglichen werden.
Inhaltsverzeichnis
- Maven-Grundlagen für Enterprise-Projekte
- Projekt A: Enterprise Multi-Module Spring Boot Service
- Projekt B: Unternehmens-BOM und Shared Libraries
- Projekt C: Legacy Jakarta EE WAR mit Application Server
- Projekt D: Batch- und Integration-Job mit Datenbankmigration
- Projekt E: Build-Quality-Gate Parent für Enterprise-Projekte
- Plugin-Erklärungen
- Dependency-Management-Erklärungen
- Build-Kommandos und typische Maven-Abläufe
- Checkliste für eigene Enterprise-POMs
- Visualisierungen: Enterprise-POMs besser verstehen
1. Maven-Grundlagen für Enterprise-Projekte
1.1 Was ist eine pom.xml?
Die pom.xml ist die zentrale Maven-Konfiguration eines Projekts. Sie beschreibt:
- Projektkoordinaten:
groupId,artifactId,version - Packaging:
jar,war,pom - Dependencies
- Dependency Management
- Plugins
- Plugin Management
- Build-Konfiguration
- Module
- Profiles
- Repositories
- Deployment-Ziele
In Enterprise-Projekten ist die POM nicht nur eine Build-Datei, sondern ein technisches Steuerungsdokument.
1.2 Parent-POM, Aggregator-POM und BOM
Parent-POM
Eine Parent-POM vererbt gemeinsame Konfigurationen an Child-Projekte.
Typische Inhalte:
- Properties
- Dependency Management
- Plugin Management
- Reporting
- Firmenweite Konventionen
Aggregator-POM
Eine Aggregator-POM enthält modules und baut mehrere Module gemeinsam.
<modules>
<module>domain</module>
<module>application</module>
<module>infrastructure</module>
</modules>
BOM
Eine BOM steht für Bill of Materials. Sie verwaltet Dependency-Versionen zentral.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme.platform</groupId>
<artifactId>acme-platform-bom</artifactId>
<version>${acme.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Wichtig: Eine BOM fügt keine Dependencies automatisch hinzu. Sie definiert nur Versionen.
1.3 dependencies vs. dependencyManagement
dependencyManagement
Hier werden Versionen zentral definiert.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
dependencies
Hier werden Dependencies tatsächlich in ein Modul eingebunden.
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
Das Modul braucht keine Version, wenn diese im Parent oder in einer importierten BOM verwaltet wird.
1.4 plugins vs. pluginManagement
pluginManagement
Definiert Plugin-Versionen und Standardkonfigurationen zentral.
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
plugins
Aktiviert Plugins wirklich im Build.
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
</plugins>
Merksatz:
pluginManagementverwaltet.pluginsführt aus.
1.5 Maven-Lifecycle
Wichtige Phasen:
| Phase | Bedeutung |
|---|---|
validate |
Projektstruktur und Konfiguration prüfen |
compile |
Produktivcode kompilieren |
test |
Unit Tests ausführen |
package |
Artefakt erstellen, z. B. JAR oder WAR |
verify |
Integrationstests und Qualitätsprüfungen ausführen |
install |
Artefakt ins lokale Maven Repository installieren |
deploy |
Artefakt in ein Remote Repository veröffentlichen |
Beispiel:
mvn clean verify
Dieser Befehl löscht alte Build-Ergebnisse und führt den Build bis zur Phase verify aus.
2. Projekt A: Enterprise Multi-Module Spring Boot Service
2.1 Szenario
Dieses Beispiel beschreibt einen modernen Enterprise-Service mit mehreren Maven-Modulen.
Fachliches Beispiel:
Ein Unternehmen betreibt einen Order-Service, der Bestellungen entgegennimmt, validiert, persistiert und Events veröffentlicht.
Architekturstil:
- Clean Architecture / Hexagonal Architecture
- Spring Boot
- REST API
- Datenbankzugriff
- Messaging
- Integrationstests
- zentrale Parent-POM
2.2 Projektstruktur
acme-order-service/
├── pom.xml
├── order-domain/
│ └── pom.xml
├── order-application/
│ └── pom.xml
├── order-infrastructure/
│ └── pom.xml
├── order-web/
│ └── pom.xml
└── order-integration-tests/
└── pom.xml
Modulrollen
| Modul | Aufgabe |
|---|---|
order-domain |
Fachmodell, Value Objects, Domain Services |
order-application |
Use Cases, Ports, Transaktionen |
order-infrastructure |
Adapter für Datenbank, Messaging, externe Systeme |
order-web |
REST Controller, Spring Boot Application |
order-integration-tests |
End-to-End- und Integrationstests |
2.3 Root-POM: acme-order-service/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme.order</groupId>
<artifactId>acme-order-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>ACME Order Service</name>
<description>Enterprise Multi-Module Order Service</description>
<modules>
<module>order-domain</module>
<module>order-application</module>
<module>order-infrastructure</module>
<module>order-web</module>
<module>order-integration-tests</module>
</modules>
<properties>
<java.version>21</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring.boot.version>4.1.0</spring.boot.version>
<junit.version>5.13.4</junit.version>
<testcontainers.version>1.21.3</testcontainers.version>
<maven.compiler.plugin.version>4.0.0-beta-3</maven.compiler.plugin.version>
<maven.surefire.plugin.version>3.5.4</maven.surefire.plugin.version>
<maven.failsafe.plugin.version>3.5.4</maven.failsafe.plugin.version>
<maven.enforcer.plugin.version>3.6.2</maven.enforcer.plugin.version>
<jacoco.plugin.version>0.8.13</jacoco.plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<useModulePath>false</useModulePath>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${maven.enforcer.plugin.version}</version>
<executions>
<execution>
<id>enforce-build-rules</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireMavenVersion>
<version>[3.9.0,)</version>
</requireMavenVersion>
<requireJavaVersion>
<version>[21,)</version>
</requireJavaVersion>
<dependencyConvergence />
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.plugin.version}</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>ci</id>
<properties>
<skip.integration.tests>false</skip.integration.tests>
</properties>
</profile>
<profile>
<id>local</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<skip.integration.tests>true</skip.integration.tests>
</properties>
</profile>
</profiles>
</project>
2.4 Erklärung der Root-POM
packaging=pom
Die Root-POM erzeugt kein JAR. Sie aggregiert Module und definiert gemeinsame Konfiguration.
modules
Die Module werden gemeinsam gebaut. Maven ermittelt die Reihenfolge anhand der Modulabhängigkeiten.
properties
Versionen und Encoding werden zentral definiert. Dadurch muss man sie später nur an einer Stelle ändern.
dependencyManagement
Die Spring-Boot-, JUnit- und Testcontainers-BOMs verwalten Versionen. Child-Module können Dependencies ohne Version verwenden.
pluginManagement
Plugin-Versionen und Standardkonfigurationen werden zentral verwaltet.
plugins
Der Enforcer und JaCoCo werden auf Root-Ebene aktiviert.
profiles
local: lokale Entwicklung, Integrationstests optional deaktiviertci: CI-Build, Integrationstests aktiv
2.5 Domain-Modul: order-domain/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.order</groupId>
<artifactId>acme-order-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>order-domain</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Erklärung
Das Domain-Modul bleibt absichtlich schlank.
Es enthält keine Spring-Boot-Starter, keine Datenbanktreiber und keine Web-Technologien. Dadurch bleibt die Fachlogik unabhängig von technischen Frameworks.
2.6 Application-Modul: order-application/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.order</groupId>
<artifactId>acme-order-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>order-application</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.acme.order</groupId>
<artifactId>order-domain</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Erklärung
Dieses Modul enthält Use Cases und Ports. Es darf das Domain-Modul kennen, aber nicht die technische Infrastruktur.
Beispielhafte Klassen:
CreateOrderUseCase
CancelOrderUseCase
OrderRepositoryPort
OrderEventPublisherPort
2.7 Infrastructure-Modul: order-infrastructure/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.order</groupId>
<artifactId>acme-order-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>order-infrastructure</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.acme.order</groupId>
<artifactId>order-application</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
</dependencies>
</project>
Erklärung
Das Infrastructure-Modul implementiert technische Adapter:
- JPA Repository Adapter
- RabbitMQ Event Publisher
- Flyway Datenbankmigrationen
- externe Client-Implementierungen
Die Abhängigkeit zeigt bewusst nach innen: Infrastruktur kennt Application, Application kennt Domain.
2.8 Web-Modul: order-web/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.order</groupId>
<artifactId>acme-order-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>order-web</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.acme.order</groupId>
<artifactId>order-application</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.acme.order</groupId>
<artifactId>order-infrastructure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Erklärung
Dieses Modul enthält die startbare Anwendung.
Das Spring Boot Maven Plugin erzeugt ein ausführbares Artefakt. In Enterprise-Umgebungen wird dieses JAR häufig als Container Image, Kubernetes Deployment oder VM-Service ausgeliefert.
2.9 Integration-Test-Modul: order-integration-tests/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.order</groupId>
<artifactId>acme-order-service</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>order-integration-tests</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.acme.order</groupId>
<artifactId>order-web</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<skipITs>${skip.integration.tests}</skipITs>
<includes>
<include>**/*IT.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Erklärung
Dieses Modul trennt Integrationstests von Unit Tests. Dateien mit Namen wie OrderApiIT.java werden über Failsafe ausgeführt.
Enterprise-Vorteil:
- Unit Tests bleiben schnell.
- Integrationstests laufen in CI zuverlässig mit echten Services via Testcontainers.
- Build-Fehler werden in der Phase
verifysichtbar.
2.10 Typische Builds für Projekt A
Lokaler schneller Build
mvn clean install -Plocal
CI-Build mit Integrationstests
mvn clean verify -Pci
Nur ein Modul und benötigte Abhängigkeiten bauen
mvn clean verify -pl order-web -am
-pl wählt ein Projekt aus.
-am baut benötigte Module mit.
3. Projekt B: Unternehmens-BOM und Shared Libraries
3.1 Szenario
Ein Unternehmen möchte Versionen, technische Standards und interne Libraries zentral verwalten.
Dieses Beispiel trennt:
- BOM für Dependency-Versionen
- Parent-POM für Build-Konventionen
- Shared Libraries für wiederverwendbare technische Komponenten
3.2 Projektstruktur
acme-platform/
├── pom.xml
├── acme-platform-bom/
│ └── pom.xml
├── acme-build-parent/
│ └── pom.xml
├── acme-logging-starter/
│ └── pom.xml
├── acme-security-starter/
│ └── pom.xml
└── acme-test-support/
└── pom.xml
3.3 Root-POM: acme-platform/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme.platform</groupId>
<artifactId>acme-platform</artifactId>
<version>2026.07.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>acme-platform-bom</module>
<module>acme-build-parent</module>
<module>acme-logging-starter</module>
<module>acme-security-starter</module>
<module>acme-test-support</module>
</modules>
</project>
3.4 BOM: acme-platform-bom/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.platform</groupId>
<artifactId>acme-platform</artifactId>
<version>2026.07.0-SNAPSHOT</version>
</parent>
<artifactId>acme-platform-bom</artifactId>
<packaging>pom</packaging>
<properties>
<spring.boot.version>4.1.0</spring.boot.version>
<jackson.version>2.20.0</jackson.version>
<logstash.encoder.version>8.1</logstash.encoder.version>
<testcontainers.version>1.21.3</testcontainers.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${jackson.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>${logstash.encoder.version}</version>
</dependency>
<dependency>
<groupId>com.acme.platform</groupId>
<artifactId>acme-logging-starter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.acme.platform</groupId>
<artifactId>acme-security-starter</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Erklärung
Diese BOM wird von fachlichen Services importiert.
Beispiel in einem Service:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme.platform</groupId>
<artifactId>acme-platform-bom</artifactId>
<version>2026.07.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Vorteil: Services definieren keine eigenen Versionen für Standardbibliotheken.
3.5 Build-Parent: acme-build-parent/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.platform</groupId>
<artifactId>acme-platform</artifactId>
<version>2026.07.0-SNAPSHOT</version>
</parent>
<artifactId>acme-build-parent</artifactId>
<packaging>pom</packaging>
<properties>
<java.version>21</java.version>
<maven.compiler.plugin.version>4.0.0-beta-3</maven.compiler.plugin.version>
<maven.enforcer.plugin.version>3.6.2</maven.enforcer.plugin.version>
<maven.surefire.plugin.version>3.5.4</maven.surefire.plugin.version>
<maven.failsafe.plugin.version>3.5.4</maven.failsafe.plugin.version>
<flatten.maven.plugin.version>1.7.3</flatten.maven.plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.acme.platform</groupId>
<artifactId>acme-platform-bom</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${maven.enforcer.plugin.version}</version>
<executions>
<execution>
<id>enterprise-rules</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>[21,)</version>
</requireJavaVersion>
<requireMavenVersion>
<version>[3.9.0,)</version>
</requireMavenVersion>
<banDuplicatePomDependencyVersions />
<dependencyConvergence />
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${flatten.maven.plugin.version}</version>
<configuration>
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten-clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Erklärung
Der Build-Parent ist kein normales Produktivmodul. Er dient als Firmenstandard.
Services können ihn als Parent verwenden:
<parent>
<groupId>com.acme.platform</groupId>
<artifactId>acme-build-parent</artifactId>
<version>2026.07.0</version>
</parent>
Dadurch gelten automatisch:
- Java-Version
- Maven-Version
- Plugin-Versionen
- Enforcer-Regeln
- zentrale Dependency-Versionen
3.6 Logging Starter: acme-logging-starter/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.platform</groupId>
<artifactId>acme-build-parent</artifactId>
<version>2026.07.0-SNAPSHOT</version>
<relativePath>../acme-build-parent/pom.xml</relativePath>
</parent>
<artifactId>acme-logging-starter</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
</dependency>
</dependencies>
</project>
Erklärung
Dieses Modul bündelt Logging-Konventionen.
Typische Inhalte:
- JSON Logging
- Correlation ID
- MDC-Konfiguration
- Standard-Logback-Konfiguration
- Maskierung sensibler Daten
3.7 Security Starter: acme-security-starter/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.platform</groupId>
<artifactId>acme-build-parent</artifactId>
<version>2026.07.0-SNAPSHOT</version>
<relativePath>../acme-build-parent/pom.xml</relativePath>
</parent>
<artifactId>acme-security-starter</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
</dependencies>
</project>
Erklärung
Dieses Modul bündelt Security-Standards:
- OAuth2 Resource Server
- JWT Validierung
- Security Filter Chain
- Rollen- und Claim-Mapping
- Standard-Fehlerantworten
4. Projekt C: Legacy Jakarta EE WAR mit Application Server
4.1 Szenario
Viele Unternehmen betreiben noch WAR-basierte Anwendungen auf Application Servern.
Dieses Beispiel zeigt:
packaging=warprovidedDependencies- Ressourcenfilterung
- separate Profile für lokale und Server-Deployments
- Integration von generiertem Code
4.2 Projektstruktur
acme-legacy-customer-portal/
├── pom.xml
├── customer-portal-web/
│ └── pom.xml
├── customer-portal-service/
│ └── pom.xml
└── customer-portal-client-generated/
└── pom.xml
4.3 Root-POM
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme.customer</groupId>
<artifactId>acme-legacy-customer-portal</artifactId>
<version>5.4.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<java.version>17</java.version>
<jakarta.ee.version>10.0.0</jakarta.ee.version>
<maven.compiler.plugin.version>4.0.0-beta-3</maven.compiler.plugin.version>
<maven.war.plugin.version>3.4.0</maven.war.plugin.version>
<build.helper.plugin.version>3.6.1</build.helper.plugin.version>
</properties>
<modules>
<module>customer-portal-client-generated</module>
<module>customer-portal-service</module>
<module>customer-portal-web</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>${jakarta.ee.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${maven.war.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${build.helper.plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
4.4 Generiertes Client-Modul
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.customer</groupId>
<artifactId>acme-legacy-customer-portal</artifactId>
<version>5.4.0-SNAPSHOT</version>
</parent>
<artifactId>customer-portal-client-generated</artifactId>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-generated-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/wsdl</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Erklärung
Dieses Modul ist für generierten Code vorgesehen, z. B. aus WSDL, XSD oder OpenAPI.
Warum ein eigenes Modul?
- generierter Code ist sauber getrennt
- weniger Vermischung mit Fachlogik
- einfacheres Caching im Build
- klare Verantwortung
4.5 Service-Modul
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.customer</groupId>
<artifactId>acme-legacy-customer-portal</artifactId>
<version>5.4.0-SNAPSHOT</version>
</parent>
<artifactId>customer-portal-service</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.acme.customer</groupId>
<artifactId>customer-portal-client-generated</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
4.6 WAR-Modul
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.customer</groupId>
<artifactId>acme-legacy-customer-portal</artifactId>
<version>5.4.0-SNAPSHOT</version>
</parent>
<artifactId>customer-portal-web</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>com.acme.customer</groupId>
<artifactId>customer-portal-service</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>customer-portal</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<webResources>
<resource>
<directory>src/main/webapp</directory>
<filtering>true</filtering>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<properties>
<target.environment>dev</target.environment>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<target.environment>prod</target.environment>
</properties>
</profile>
</profiles>
</project>
Erklärung
provided bedeutet: Die API wird zum Kompilieren benötigt, aber nicht ins WAR gepackt, weil der Application Server sie bereitstellt.
Typisches Deployment:
mvn clean package -Pprod
Ergebnis:
target/customer-portal.war
5. Projekt D: Batch- und Integration-Job mit Datenbankmigration
5.1 Szenario
Ein Enterprise-Batch-Job verarbeitet nächtlich CSV-Dateien, schreibt Daten in PostgreSQL und veröffentlicht Events.
Dieses Beispiel zeigt:
- Spring Boot Batch-Anwendung
- Flyway Migrationen
- Failsafe Integrationstests
- Docker Image Build mit Jib
- getrennte Profile für
local,ci,release
5.2 Projektstruktur
acme-billing-batch/
├── pom.xml
├── billing-batch-core/
│ └── pom.xml
├── billing-batch-app/
│ └── pom.xml
└── billing-batch-it/
└── pom.xml
5.3 Root-POM
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme.billing</groupId>
<artifactId>acme-billing-batch</artifactId>
<version>2.8.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>billing-batch-core</module>
<module>billing-batch-app</module>
<module>billing-batch-it</module>
</modules>
<properties>
<java.version>21</java.version>
<spring.boot.version>4.1.0</spring.boot.version>
<jib.plugin.version>3.4.6</jib.plugin.version>
<flyway.plugin.version>11.13.2</flyway.plugin.version>
<maven.failsafe.plugin.version>3.5.4</maven.failsafe.plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin.version}</version>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>${jib.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>${flyway.plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
5.4 Core-Modul
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.billing</groupId>
<artifactId>acme-billing-batch</artifactId>
<version>2.8.0-SNAPSHOT</version>
</parent>
<artifactId>billing-batch-core</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
</dependencies>
</project>
5.5 App-Modul mit Spring Boot und Jib
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.billing</groupId>
<artifactId>acme-billing-batch</artifactId>
<version>2.8.0-SNAPSHOT</version>
</parent>
<artifactId>billing-batch-app</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.acme.billing</groupId>
<artifactId>billing-batch-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<configuration>
<from>
<image>eclipse-temurin:21-jre</image>
</from>
<to>
<image>registry.acme.example/billing/billing-batch:${project.version}</image>
</to>
<container>
<mainClass>com.acme.billing.BillingBatchApplication</mainClass>
<creationTime>USE_CURRENT_TIMESTAMP</creationTime>
</container>
</configuration>
</plugin>
</plugins>
</build>
</project>
Erklärung
Das App-Modul ist startbar und kann ein Container Image bauen.
Typische Befehle:
mvn clean package
mvn -pl billing-batch-app jib:build
5.6 Integration-Test-Modul
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.acme.billing</groupId>
<artifactId>acme-billing-batch</artifactId>
<version>2.8.0-SNAPSHOT</version>
</parent>
<artifactId>billing-batch-it</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.acme.billing</groupId>
<artifactId>billing-batch-app</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
5.7 Flyway-Migrationen ausführen
In echten Projekten wird Flyway häufig durch die Anwendung selbst ausgeführt. Manchmal möchte man Migrationen explizit per Maven starten.
Beispiel:
mvn -pl billing-batch-app flyway:migrate \
-Dflyway.url=jdbc:postgresql://localhost:5432/billing \
-Dflyway.user=billing \
-Dflyway.password=secret
Enterprise-Hinweis:
Passwörter gehören nicht in die POM. Sie sollten über CI-Secrets, Umgebungsvariablen oder Maven settings.xml kommen.
6. Projekt E: Build-Quality-Gate Parent für Enterprise-Projekte
6.1 Szenario
Ein Unternehmen möchte Qualitätssicherung standardisieren.
Dieser Parent erzwingt:
- Java-Version
- Maven-Version
- Dependency-Konvergenz
- Unit Tests
- Integrationstests
- Code Coverage
- statische Analyse
- reproduzierbare Builds
6.2 Projektstruktur
acme-quality-parent/
└── pom.xml
6.3 Quality Parent POM
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme.quality</groupId>
<artifactId>acme-quality-parent</artifactId>
<version>1.3.0</version>
<packaging>pom</packaging>
<properties>
<java.version>21</java.version>
<maven.compiler.plugin.version>4.0.0-beta-3</maven.compiler.plugin.version>
<maven.enforcer.plugin.version>3.6.2</maven.enforcer.plugin.version>
<maven.surefire.plugin.version>3.5.4</maven.surefire.plugin.version>
<maven.failsafe.plugin.version>3.5.4</maven.failsafe.plugin.version>
<jacoco.plugin.version>0.8.13</jacoco.plugin.version>
<spotbugs.plugin.version>4.9.4.0</spotbugs.plugin.version>
<checkstyle.plugin.version>3.6.0</checkstyle.plugin.version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<release>${java.version}</release>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${maven.enforcer.plugin.version}</version>
<executions>
<execution>
<id>enforce-enterprise-standards</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>[21,)</version>
</requireJavaVersion>
<requireMavenVersion>
<version>[3.9.0,)</version>
</requireMavenVersion>
<dependencyConvergence />
<banDuplicatePomDependencyVersions />
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven.failsafe.plugin.version}</version>
<configuration>
<includes>
<include>**/*IT.java</include>
</includes>
</configuration>
<executions>
<execution>
<id>integration-tests</id>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.plugin.version}</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>check</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>${spotbugs.plugin.version}</version>
<configuration>
<effort>Max</effort>
<threshold>Medium</threshold>
<failOnError>true</failOnError>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${checkstyle.plugin.version}</version>
<configuration>
<configLocation>acme-checkstyle.xml</configLocation>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>quality</id>
<build>
<plugins>
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
6.4 Erklärung
Dieser Parent trennt normale Build-Regeln von teuren Quality Checks.
Standard-Build:
mvn clean verify
Build mit statischer Analyse:
mvn clean verify -Pquality
Enterprise-Vorteil:
- Teams haben eine gemeinsame Qualitätsbasis.
- CI/CD kann Quality Gates erzwingen.
- Plugin-Versionen sind zentral kontrolliert.
- Build-Verhalten wird reproduzierbarer.
7. Plugin-Erklärungen
7.1 maven-compiler-plugin
Zweck
Kompiliert Java-Code.
Wichtige Konfiguration
<release>${java.version}</release>
release ist in modernen Builds meist besser als getrennte source- und target-Werte, weil nicht nur Bytecode-Version, sondern auch verfügbare Java-API berücksichtigt wird.
Enterprise-Relevanz
- verhindert versehentliche Nutzung falscher Java-Versionen
- sorgt für konsistente Artefakte
- wichtig für CI/CD und Runtime-Kompatibilität
7.2 maven-surefire-plugin
Zweck
Führt Unit Tests aus.
Typische Testnamen
*Test.java
*Tests.java
Lifecycle
Surefire läuft typischerweise in der Phase test.
7.3 maven-failsafe-plugin
Zweck
Führt Integrationstests aus.
Typische Testnamen
*IT.java
*ITCase.java
Lifecycle
Failsafe wird typischerweise an diese Phasen gebunden:
integration-testverify
Warum nicht Surefire?
Integrationstests brauchen häufig externe Systeme wie Datenbank, Message Broker oder Testcontainers. Failsafe behandelt Fehler so, dass Cleanup-Schritte im Maven-Lifecycle zuverlässiger ausgeführt werden können.
7.4 maven-enforcer-plugin
Zweck
Erzwingt Build-Regeln.
Beispiele:
- minimale Maven-Version
- minimale Java-Version
- Dependency-Konvergenz
- keine doppelten Dependency-Versionen
Enterprise-Relevanz
Sehr wichtig, weil in großen Organisationen viele Teams mit unterschiedlichen lokalen Setups arbeiten.
7.5 jacoco-maven-plugin
Zweck
Misst Testabdeckung.
Typische Ziele
prepare-agentreportcheck
Enterprise-Relevanz
Ermöglicht messbare Quality Gates, z. B. mindestens 80 Prozent Line Coverage.
Wichtig: Coverage ist kein Qualitätsbeweis, aber ein nützlicher Mindestindikator.
7.6 spring-boot-maven-plugin
Zweck
Unterstützt Spring Boot in Maven.
Typische Aufgaben:
- ausführbares JAR oder WAR erzeugen
- Anwendung starten
- Build-Informationen erzeugen
- Repackage eines Artefakts
Enterprise-Relevanz
Wichtig für Microservices, Containerisierung und Cloud Deployments.
7.7 maven-war-plugin
Zweck
Erstellt WAR-Dateien.
Typischer Einsatz
- klassische Webanwendungen
- Deployment auf Application Servern
- Legacy-Jakarta-EE-Projekte
7.8 flatten-maven-plugin
Zweck
Erzeugt eine vereinfachte POM für Veröffentlichung.
Enterprise-Relevanz
Nützlich bei CI-freundlichen Versionen, Parent-Strukturen und internen Artefakt-Repositories.
7.9 jib-maven-plugin
Zweck
Baut Container Images für Java-Anwendungen ohne klassisches Dockerfile.
Enterprise-Relevanz
Hilfreich für CI/CD, wenn Container Images standardisiert erzeugt und in eine Registry gepusht werden sollen.
7.10 flyway-maven-plugin
Zweck
Führt Datenbankmigrationen aus.
Enterprise-Relevanz
Datenbankschemata werden versioniert und reproduzierbar ausgerollt.
Wichtig: Zugangsdaten gehören nicht in die POM.
7.11 build-helper-maven-plugin
Zweck
Erweitert den Build, z. B. durch zusätzliche Source-Verzeichnisse.
Typische Verwendung
- generierte Quellen einbinden
- zusätzliche Test-Sources registrieren
- Build-Metadaten erzeugen
7.12 spotbugs-maven-plugin
Zweck
Findet potenzielle Fehler im Bytecode.
Enterprise-Relevanz
Hilft bei großen Codebasen, riskante Muster automatisiert zu erkennen.
7.13 maven-checkstyle-plugin
Zweck
Prüft Code-Style-Regeln.
Enterprise-Relevanz
Sorgt für einheitlichen Stil über Teams hinweg.
8. Dependency-Management-Erklärungen
8.1 Warum BOMs verwenden?
BOMs reduzieren Versionschaos.
Ohne BOM:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>4.1.0</version>
</dependency>
Mit BOM:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Die Version kommt aus dependencyManagement.
8.2 Interne BOM vs. externe BOM
Externe BOM
Beispiele:
- Spring Boot BOM
- JUnit BOM
- Testcontainers BOM
- Jackson BOM
Interne BOM
Eine interne BOM verwaltet zusätzlich Firmenbibliotheken.
Beispiel:
<dependency>
<groupId>com.acme.platform</groupId>
<artifactId>acme-security-starter</artifactId>
<version>${project.version}</version>
</dependency>
8.3 Typische Dependency Scopes
| Scope | Erklärung | Beispiel |
|---|---|---|
compile |
Standard, zur Compile- und Laufzeit verfügbar | Fachbibliothek |
provided |
Compile-Zeit, aber Runtime stellt es bereit | Jakarta EE API im Application Server |
runtime |
Nur zur Laufzeit nötig | JDBC-Treiber |
test |
Nur für Tests | JUnit, Testcontainers |
import |
Nur für BOM-Import in dependencyManagement |
Spring Boot BOM |
8.4 Transitive Dependencies
Maven lädt nicht nur direkte Dependencies, sondern auch deren Abhängigkeiten.
Problem:
service-a -> library-x -> vulnerable-lib:1.0
service-a -> library-y -> vulnerable-lib:2.0
Mögliche Folge:
- Versionskonflikte
- Security-Probleme
- unerwartetes Laufzeitverhalten
Gegenmaßnahmen:
- BOMs
- Dependency Convergence Checks
- Security Scans
- gezielte Exclusions
- regelmäßige Updates
9. Build-Kommandos und typische Maven-Abläufe
9.1 Komplettes Projekt bauen
mvn clean install
9.2 Projekt bis Quality-Gate bauen
mvn clean verify
9.3 Mit Profil bauen
mvn clean verify -Pci
9.4 Einzelnes Modul bauen
mvn clean install -pl order-web
9.5 Einzelnes Modul plus benötigte Module bauen
mvn clean install -pl order-web -am
9.6 Abhängige Module ebenfalls bauen
mvn clean install -pl order-domain -amd
9.7 Dependency Tree anzeigen
mvn dependency:tree
9.8 Effektive POM anzeigen
mvn help:effective-pom
Sehr hilfreich, um Vererbung, Profile und Plugin-Konfigurationen zu verstehen.
10. Checkliste für eigene Enterprise-POMs
10.1 Struktur
- Gibt es eine klare Root-POM?
- Ist
packaging=pombei Aggregatoren korrekt gesetzt? - Sind Module logisch getrennt?
- Gibt es eine klare Parent-POM?
- Ist eine BOM sinnvoll?
10.2 Versionen
- Werden Dependency-Versionen zentral verwaltet?
- Werden Plugin-Versionen zentral verwaltet?
- Gibt es harte Versionen in Child-Modulen?
- Gibt es Snapshot-Dependencies in Release-Builds?
10.3 Build
- Ist Java-Version eindeutig definiert?
- Nutzt der Compiler
release? - Sind Unit Tests und Integrationstests getrennt?
- Sind Plugin-Versionen fixiert?
- Gibt es Enforcer-Regeln?
10.4 Sicherheit
- Gibt es Dependency-Konvergenzprüfungen?
- Gibt es Security Scans in CI?
- Werden Secrets aus der POM herausgehalten?
- Gibt es eine Regel gegen unsichere Repositories?
10.5 Deployment
- Ist
distributionManagementkorrekt? - Sind Snapshot- und Release-Repositories getrennt?
- Werden Container Images reproduzierbar gebaut?
- Ist klar, welches Modul deployt wird?
10.6 Wartbarkeit
- Sind Profiles verständlich benannt?
- Sind Properties sprechend?
- Sind technische Starter sinnvoll getrennt?
- Gibt es Dokumentation für jedes Modul?
- Ist
mvn help:effective-pomnachvollziehbar?
11. Empfohlenes Lernvorgehen
Schritt 1: Root-POM lesen
Fragen:
- Welche Module gibt es?
- Welche Versionen sind zentral definiert?
- Welche BOMs werden importiert?
- Welche Plugins sind zentral verwaltet?
Schritt 2: Modul-POMs lesen
Fragen:
- Welche Aufgabe hat das Modul?
- Welche internen Module werden verwendet?
- Welche externen Libraries werden verwendet?
- Welche Scopes kommen vor?
Schritt 3: Effektive POM erzeugen
mvn help:effective-pom
Damit sieht man die finale Maven-Konfiguration nach Vererbung und Profilauflösung.
Schritt 4: Dependency Tree prüfen
mvn dependency:tree
Damit sieht man transitive Dependencies und mögliche Konflikte.
Schritt 5: Build-Lifecycle verstehen
mvn clean verify -X
-X erzeugt Debug-Ausgabe. Für Anfänger ist das sehr viel, aber für tiefe Fehleranalyse nützlich.
12. Zusammenfassung
Dieses Buch hat fünf Enterprise-Maven-Beispiele gezeigt:
Multi-Module Spring Boot Service
Moderne Microservice-Struktur mit Domain, Application, Infrastructure, Web und Integration Tests.Unternehmens-BOM und Shared Libraries
Zentrale Dependency- und Build-Standards für mehrere Teams.Legacy Jakarta EE WAR
Klassische Enterprise-Webanwendung für Application Server.Batch- und Integration-Job
Batch-Verarbeitung mit Datenbankmigration, Integrationstests und Container Image Build.Quality-Gate Parent
Firmenweiter Parent für Build-Regeln, Tests, Coverage und statische Analyse.
Die wichtigsten Maven-Prinzipien sind:
- Versionen zentralisieren
- Build-Konventionen standardisieren
- Parent-POM, BOM und Aggregator sauber trennen
- Unit Tests und Integrationstests getrennt ausführen
- Secrets nie in POM-Dateien speichern
- CI/CD als Teil des Build-Designs betrachten
dependencyManagementundpluginManagementbewusst einsetzen
13. Mini-Glossar
| Begriff | Bedeutung |
|---|---|
| POM | Project Object Model, zentrale Maven-Konfiguration |
| Parent-POM | Vererbt gemeinsame Einstellungen |
| Aggregator-POM | Baut mehrere Module gemeinsam |
| BOM | Bill of Materials, zentrale Dependency-Versionen |
| Plugin | Maven-Erweiterung für Build-Aufgaben |
| Goal | Einzelne Aufgabe eines Plugins |
| Phase | Schritt im Maven-Lifecycle |
| Profile | Build-Variante für Umgebung oder Zweck |
| Scope | Gültigkeitsbereich einer Dependency |
| Transitive Dependency | Indirekte Abhängigkeit über andere Libraries |
| Effective POM | Finale POM nach Vererbung und Profilauflösung |
14. Quellen und Referenzen
Die Beispiele orientieren sich an den offiziellen Maven- und Spring-Boot-Konzepten:
- Apache Maven POM Reference
- Apache Maven Introduction to the Build Lifecycle
- Apache Maven Introduction to Build Profiles
- Apache Maven Multiple Modules Guide
- Apache Maven Compiler Plugin Dokumentation
- Spring Boot Maven Plugin Dokumentation
11. Visualisierungen: Enterprise-POMs besser verstehen
Dieses Kapitel ergänzt das Beispielbuch um zusätzliche SVG-Diagramme. Die Bilder sind bewusst nicht als Dekoration gedacht, sondern als Lesehilfe für komplexe POM-Dateien. Nutze sie, wenn du eine fremde Unternehmens-POM analysierst oder eigene Build-Standards dokumentieren möchtest.
11.1 POM als Enterprise-Vertrag
Was zeigt das Diagramm?
Die pom.xml steht in der Mitte, weil viele Unternehmensstandards dort zusammenlaufen. Links liegen Dependencies und Plugins, rechts Profiles und Repositories. Oben wirken Parent-POM oder BOM hinein; unten wird daraus ein CI/CD-Build.
Warum ist das wichtig?
In Enterprise-Projekten ist eine POM oft ein Vertrag: Sie legt fest, welche Versionen erlaubt sind, wie getestet wird, wie Artefakte heißen und wohin sie deployed werden.
So liest du das in echten Projekten:
Prüfe zuerst Parent, dependencyManagement, pluginManagement, Profiles und distributionManagement. Danach erst einzelne Dependencies oder Plugin-Details.
11.2 Effective POM: Was Maven wirklich sieht
Was zeigt das Diagramm?
Maven kombiniert die Super POM, Unternehmens-Parent, Modul-POM und aktive Profiles zu einer endgültigen Konfiguration.
Warum ist das wichtig?
Viele Build-Probleme sind nicht direkt in der sichtbaren Modul-POM erkennbar, weil Versionen, Plugin-Konfigurationen oder Repositories geerbt werden.
Praxisbefehl:
mvn help:effective-pom
mvn help:effective-settings
11.3 BOM-Layering in Enterprise-Projekten
Was zeigt das Diagramm?
Externe BOMs wie Spring Boot, Testcontainers oder Cloud-BOMs werden in einer eigenen Platform-BOM gebündelt. Services nutzen danach Dependencies ohne lokale Versionsduplikate.
Warum ist das wichtig?
Ohne zentrale BOM entstehen Versionsdrift, Sicherheitslücken und schwer nachvollziehbare Konflikte zwischen Teams.
Analysefrage:
Welche Versionen stehen in Child-POMs direkt und welche kommen aus einer BOM? Direkte Versionen in vielen Child-POMs sind oft ein Wartungsrisiko.
11.4 pluginManagement vs. plugins
Was zeigt das Diagramm?
Die Parent-POM definiert Versionen und Standardkonfigurationen. Ein Modul aktiviert das Plugin im plugins-Block. Maven führt Plugin-Goals dann in Lifecycle-Phasen wie compile, test oder verify aus.
Typischer Fehler:
Ein Plugin steht nur in pluginManagement, wird aber nie unter plugins aktiviert. Dann ist es zwar verwaltet, läuft aber nicht automatisch.
11.5 Dependency-Auflösung und Konflikte
Was zeigt das Diagramm?
Ein Service bringt direkte Dependencies mit. Diese bringen wiederum transitive Dependencies. Wenn zwei Pfade verschiedene Versionen derselben Library liefern, muss die Entscheidung nachvollziehbar sein.
Praxisbefehle:
mvn dependency:tree
mvn dependency:tree -Dincludes=org.slf4j
mvn dependency:tree -Dverbose
11.6 Modulgrenzen und Verantwortlichkeiten
Was zeigt das Diagramm?
Ein Root-Aggregator baut Shared Libraries, Event Contracts, Services und Test-Hilfen gemeinsam. Die Pfeile zeigen, welche Module andere Module verwenden.
Warum ist das wichtig?
Ein Multi-Module-Build wird schwer wartbar, wenn alle Module alles voneinander kennen. Gute Grenzen reduzieren Build-Zeit, Kopplung und Release-Risiko.
11.7 Profiles und Umgebungen
Was zeigt das Diagramm?
dev, test/ci und prod unterscheiden sich häufig bei Datenbank, Tests, Quality Gates und Artefakt-Strategie.
Best Practice:
Vermeide Profiles, die den Build komplett verändern. Profiles sollten Unterschiede sichtbar und begrenzt halten.
11.8 CI-Quality-Pipeline
Was zeigt das Diagramm?
Der Build beginnt mit Enforcer-Regeln, kompiliert Code, führt Unit Tests aus, prüft Integrationstests und Qualitätsmetriken und veröffentlicht erst danach Artefakte.
Typische Pull-Request-Regel:
mvn -B clean verify -Pci
11.9 Snapshot- und Release-Fluss
Was zeigt das Diagramm?
Feature-Branches erzeugen häufig SNAPSHOT-Artefakte. Ein Release-Branch oder Tag erzeugt unveränderbare Release-Artefakte.
Wichtige POM-Stelle:
distributionManagement entscheidet, wohin mvn deploy veröffentlicht.
11.10 Maven-Troubleshooting-Fluss
Was zeigt das Diagramm?
Ein Build-Fehler wird zuerst grob sortiert: Dependency, Plugin, Test oder Umgebung/Profile. Danach nutzt man gezielte Maven-Befehle.
Debug-Werkzeuge:
mvn -X clean verify
mvn help:effective-pom
mvn dependency:tree
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-surefire-plugin