Master 2.1

Master 2.1 Lernbuch Desktop

Projektbeschreibungen, Ablauf und Modulzweck wurden direkt in den Maven-Workspace integriert.

Master 2 Lernbuch - Moderne Enterprise Maven Modular Projekte

Architekturueberblick Master 2

Master 2 erweitert den ersten Maven-Master zu einer groesseren Enterprise-Referenz. Der Workspace ist auf fachliche Modulgrenzen, klare Abhaengigkeiten und austauschbare Infrastruktur ausgelegt.

Hexagonal Architecture

Zielbild

Die Domain kennt keine REST-Controller, keine JPA-Entities, keine Kafka-Templates und keine Framework-Bootstrapping-Klassen. Application Services orchestrieren Use Cases ueber Ports. Adapter implementieren technische Details.

Modulgruppen

Gruppe Module Zweck
Plattform platform-bom, Parent POM Versionen, PluginManagement, Enforcer
Shared Kernel shared-kernel Money, Result, DomainEvent, IdempotencyKey
Domain order-domain, customer-domain, inventory-domain, pricing-domain, payment-domain Fachmodell und Regeln
Application order-application Use Cases, Commands, Transactions-Port
Integration integration-outbox Outbox, Relay, Saga
Adapter REST, JPA, Kafka, Legacy ACL Infrastruktur und Schnittstellen
Apps Spring Boot, Quarkus Laufzeitvarianten
Tests architecture-tests ArchUnit-Regeln und Pattern-Pruefung

Warum Maven modular?

Maven macht Abhaengigkeiten sichtbar. Wenn Domain-Module aus Versehen Spring oder JPA importieren, faellt das im Build und in Architekturtests auf.

Maven Reactor

Lernfokus

  • Reactor verstehen: Parent, BOM, Module, pluginManagement.
  • Ports and Adapters praktisch sehen.
  • Fachliche Patterns direkt im Code finden.
  • Outbox/Saga als Enterprise-Integrationsmuster verstehen.
  • Spring Boot und Quarkus als alternative Runtimes ueber denselben Use Case vergleichen.

Maven Deep Dive

Parent POM

Der Parent POM definiert gemeinsame Java-Version, Plugin-Versionen und Module. Er soll nicht unkontrolliert Abhaengigkeiten in alle Module pumpen. Deshalb werden viele Abhaengigkeiten nur in den konkreten Modul-POMs gesetzt.

<modules>
  <module>shared-kernel</module>
  <module>order-domain</module>
  <module>order-application</module>
  <module>adapters-rest-spring</module>
  <module>app-spring-boot</module>
</modules>

Dependency Management

Dependency Management legt Versionen zentral fest. Ein Modul entscheidet trotzdem selbst, ob es die Dependency braucht.

Plugin Management

Plugin Management vermeidet Versionsdrift. Der Compiler verwendet bewusst release, damit Source, Target und Bootclasspath konsistent sind.

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <release>${java.version}</release>
  </configuration>
</plugin>

Reactor-Strategie

In grossen Projekten baust du selten alles. Beispiele:

mvn -pl order-domain test
mvn -pl app-spring-boot -am verify
mvn -pl architecture-tests -am test

-pl waehlt Module, -am baut benoetigte Abhaengigkeiten mit.

Typische Enterprise-Regel

Domain-Module duerfen keine Framework-Starter importieren. REST/JPA/Kafka gehoeren in Adaptermodule.

Entwurfsmuster im Maven Master 2

Aggregate Root

Zweck: Konsistenzgrenze fuer Bestellungen

Einsatzort: order-domain/Order.java

Begruendung: Zentralisiert Invarianten und Events

Value Object

Zweck: Unveraenderliche Fachwerte

Einsatzort: shared-kernel/Money.java, order-domain/OrderLine.java

Begruendung: Verhindert Primitive Obsession

Repository

Zweck: Persistenz-Port im Domain-Modell

Einsatzort: order-domain/OrderRepository.java

Begruendung: Domain bleibt DB-neutral

Factory Method

Zweck: Kontrollierte Aggregate-Erzeugung

Einsatzort: Order.start(), OrderId.newId()

Begruendung: Keine ungueltigen Startzustaende

Domain Event

Zweck: Fachliche Ereignisse explizit machen

Einsatzort: OrderPlaced.java

Begruendung: Entkopplung von Folgeprozessen

Specification

Zweck: Regeln kombinierbar ausdruecken

Einsatzort: OrderSpecification.java

Begruendung: Testbare Fachbedingungen

Strategy

Zweck: Preislogik austauschbar machen

Einsatzort: PricingStrategy.java

Begruendung: Varianten ohne if-Kaskaden

Policy

Zweck: Fachentscheidung kapseln

Einsatzort: CustomerCreditPolicy, InventoryReservationPolicy

Begruendung: Regeln bleiben eigenstaendig

Application Service

Zweck: Use Case orchestrieren

Einsatzort: PlaceOrderService.java

Begruendung: Keine Framework-Logik in Domain

Command

Zweck: Benutzerabsicht transportieren

Einsatzort: PlaceOrderCommand.java

Begruendung: Eingabe bleibt explizit und testbar

CQRS

Zweck: Lesen und Schreiben trennen

Einsatzort: OrderQueryService.java

Begruendung: Read Model darf optimiert sein

Adapter

Zweck: Technologie an Ports anschliessen

Einsatzort: REST, JPA, Kafka, Legacy

Begruendung: Austauschbarkeit

Facade

Zweck: Einheitliche REST-Fehler

Einsatzort: RestExceptionMapper.java

Begruendung: API bleibt konsistent

Data Mapper

Zweck: Entity von Domain trennen

Einsatzort: OrderEntity.java

Begruendung: JPA leakt nicht in Aggregate

Unit of Work

Zweck: Transaktionsgrenze kapseln

Einsatzort: TransactionBoundary.java

Begruendung: Application bleibt Framework-neutral

Transactional Outbox

Zweck: Dual-Writes vermeiden

Einsatzort: OutboxRecord.java

Begruendung: Event und Fachzustand in einer TX

Saga

Zweck: Verteilte Prozesse koordinieren

Einsatzort: PaymentSaga.java

Begruendung: Keine globale XA-Transaktion

Anti-Corruption Layer

Zweck: Legacy entkoppeln

Einsatzort: LegacyOrderGateway.java

Begruendung: Alte Modelle kontaminieren Domain nicht

Gateway

Zweck: Externes System kapseln

Einsatzort: LegacySoapClient.java

Begruendung: Technischer Zugriff bleibt schmal

Idempotent Consumer

Zweck: Retry-sicher verarbeiten

Einsatzort: IdempotentConsumerGuard.java

Begruendung: Doppelte Messages werden unschaedlich

Composition Root

Zweck: Verdrahtung zentralisieren

Einsatzort: EnterpriseSpringApplication, Quarkus Wiring

Begruendung: Domain baut keine Infrastruktur

Fitness Function

Zweck: Architektur pruefbar machen

Einsatzort: LayerRulesTest.java

Begruendung: Regeln werden Build-Bestandteil

Outbox und Saga Deep Dive

Outbox Saga Flow

Problem

Ein Bestellservice soll eine Bestellung speichern und ein Event publizieren. Wenn erst die Datenbank schreibt und danach Kafka fehlschlaegt, entsteht ein inkonsistenter Zustand. Wenn erst Kafka publiziert und danach die Datenbank fehlschlaegt, entsteht ebenfalls Inkonsistenz.

Loesung: Transactional Outbox

Die Fachtransaktion schreibt Bestellung und Outbox-Datensatz gemeinsam. Ein Relay publiziert spaeter zuverlaessig.

// PATTERN: Transactional Outbox
orders.save(order);
order.domainEvents().forEach(outbox::append);

Saga

Eine Saga koordiniert laengere Prozesse wie Zahlung, Reservierung, Versand. Jeder Schritt hat Kompensationen oder klare Fehlerzustaende.

Wann sinnvoll?

  • Payment und Fulfillment sind getrennte Systeme.
  • Messaging ist asynchron.
  • Kein globales XA ueber alle Systeme gewuenscht.
  • Retries und Idempotenz sind Pflicht.

CQRS und Read Models

CQRS

Idee

Das Schreibmodell schuetzt Invarianten. Das Lesemodell beantwortet Abfragen schnell und bequem. Dadurch muss das Aggregate nicht fuer Reporting, Suchlisten oder Dashboard-Zwecke verbogen werden.

Im Projekt

OrderQueryService ist bewusst von PlaceOrderUseCase getrennt. In einem echten Projekt koennte der Query-Service auf eine Projection-Tabelle, Elasticsearch, OpenSearch oder eine Materialized View zugreifen.

Merksatz

CQRS ist nicht automatisch Event Sourcing. CQRS bedeutet zuerst nur: Schreiben und Lesen werden getrennt modelliert.

Security und Observability

Pipeline

Security

Master 2 zeigt Security als Querschnitt, nicht als Domain-Bestandteil. Authentifizierung, Token-Validierung und technische Policies bleiben in App- und Adaptermodulen.

Observability

Spring Boot Actuator und Quarkus Health/Micrometer bilden Health, Metrics und Prometheus-Ausgabe ab. Fachliche Events sind nicht nur fuer Integration nuetzlich, sondern auch fuer Auditing und Diagnostik.

Build Gates

  • Maven Enforcer fuer Java/Maven-Versionen.
  • Architecture Tests fuer Layer-Regeln.
  • Dependency Analyse und Lizenzbericht.
  • Pattern-Marker-Test als Dokumentationsschutz.

Runbook

Lokaler Build

cd mvn-ws-sb3-quarkus-jpa-kafka
mvn -DskipTests verify

Nur Domain pruefen

mvn -pl order-domain,order-application test

Spring Boot App starten

mvn -pl app-spring-boot -am spring-boot:run

Quarkus App starten

mvn -pl app-quarkus -am quarkus:dev

Architekturtests

mvn -pl architecture-tests -am test

Was lokal mit Internet passiert

Maven laedt beim ersten Lauf externe Dependencies. Im ZIP sind keine externen JARs enthalten.

Glossar

Aggregate

Eine Konsistenzgrenze im Domain Model. Von aussen wird nur die Aggregate Root veraendert.

Adapter

Technische Umsetzung eines Ports. Beispiele: REST Controller, JPA Repository, Kafka Publisher, SOAP Client.

Anti-Corruption Layer

Schutzschicht gegen Legacy-Modelle. Alte Datenformen werden uebersetzt, bevor sie die neue Domain erreichen.

BOM

Bill of Materials. Zentralisiert Dependency-Versionen, ohne automatisch jede Dependency in jedes Modul zu ziehen.

Composition Root

Ort, an dem konkrete Implementierungen zusammengesetzt werden. In Spring ist das typischerweise Configuration/Bootstrapping.

Domain Event

Fachliches Ereignis wie OrderPlaced. Es beschreibt, was passiert ist, nicht was technisch als naechstes aufgerufen werden soll.

Outbox

Persistenter Zwischenspeicher fuer zu publizierende Events. Vermeidet Dual-Write-Probleme.

Port

Schnittstelle, die von der Application oder Domain benoetigt wird. Adapter implementieren Ports.

Reactor

Mavens Mechanismus, um Multi-Module-Projekte in korrekter Reihenfolge zu bauen.

Versionsannahmen und Quellenstand

Stand: 2026-07-07.

Baustein Im Projekt verwendet Hinweis
Java 21 Enterprise-LTS-freundlich und kompatibel mit modernen Frameworks
Spring Boot 4.1.0 Parent nutzt Spring Boot BOM und Plugin
Quarkus 3.37.1 BOM und Maven Plugin im Parent
Jakarta EE 11 Dokumentations- und API-Zielbild
Maven Compiler Plugin 3.15.0 release-Konfiguration
Maven Enforcer Plugin 3.6.3 Build-Regeln
Maven Dependency Plugin 3.11.0 Analyse/Reports

Die Versionen wurden im Master-POM zentralisiert, damit spaetere Deep-Dive-Versionen nur Properties aktualisieren muessen.

Master 2.1 Projektbeschreibungen und Ablauf

Dieses Dokument beschreibt kurz, was jedes Maven-Modul tut und wie der fachliche Ablauf durch die Module laeuft. Die gleichen Beschreibungen sind zusaetzlich direkt in den einzelnen Modulordnern als README.md und README.html integriert.

Fachlicher End-to-End-Ablauf

  1. HTTP Eingang: adapters-rest-spring oder app-quarkus nimmt eine Bestellung entgegen.
  2. Command: Der Eingang wird in PlaceOrderCommand uebersetzt.
  3. Use Case: order-application orchestriert Kreditpruefung, Lagerpruefung, Preislogik, Bestellung und Transaktionsgrenze.
  4. Domain: order-domain erzwingt Invarianten und erzeugt OrderPlaced.
  5. Persistenz: adapters-persistence-jpa speichert Bestellung und technische Transaktion.
  6. Outbox: integration-outbox speichert Event-Auslieferungsabsicht und liefert spaeter aus.
  7. Messaging: adapters-messaging-kafka publiziert Events und schuetzt Konsumenten mit Idempotenz.
  8. Legacy: adapters-legacy-acl kapselt altes SOAP-/Legacy-Modell.
  9. Runtime: app-spring-boot oder app-quarkus startet die gewuenschte Laufzeit.
  10. Qualitaet: architecture-tests prueft Modulgrenzen, Pattern-Marker und Architekturregeln.

Moduluebersicht

Modul Typ Was es tut Ablaufrolle
platform-bom Maven-BOM / Build Governance Zentralisiert Versionsverwaltung und gemeinsame Test-/Architektur-Bibliotheken, damit alle Module reproduzierbar dieselben Dependency-Versionen verwenden. Wird zuerst im Reactor gelesen.; Andere Module importieren oder verwenden die verwalteten Versionen indirekt ueber den Parent.
shared-kernel Domain Foundation Enthaelt kleine, stabile Bausteine, die mehrere fachliche Bounded Contexts gemeinsam benutzen duerfen. Domain-Module haengen von shared-kernel ab.; Aggregate registrieren Domain Events.
order-domain Kern-Domain Modelliert Bestellung, Bestellpositionen, Status, Repository-Port und fachliche Spezifikationen. PlaceOrderService erstellt Order aus Command-Daten.; Order prueft Invarianten und registriert Domain Events.
customer-domain Bounded Context Kapselt Kundenregeln, besonders Kredit- und Freigabeentscheidungen fuer Bestellungen. Order Application fragt Credit Policy vor dem Platzieren.; Policy entscheidet anhand Kundendaten und Risiko.
inventory-domain Bounded Context Beschreibt Reservierungsregeln fuer Lagerbestand, ohne direkt von Datenbank oder Messaging abzuhaengen. Order Application prueft Reservierbarkeit.; Inventory Policy bewertet Positionen.
pricing-domain Bounded Context Berechnet Preise ueber austauschbare Strategien, damit Rabatt-, Staffel- oder Kampagnenlogik nicht im Order Aggregate landet. Use Case uebergibt Warenkorb oder Positionen an Pricing Strategy.; Strategie berechnet Money-Werte.
payment-domain Bounded Context / Port Definiert die Zahlungsintegration als Port, damit echte Provider, Mocks oder Legacy-Zahlungssysteme austauschbar bleiben. PaymentSaga oder Application ruft PaymentGatewayPort.; Ein Adapter fuehrt die echte Zahlung aus.
fulfillment-domain Bounded Context Plant Versand- oder Erfuellungsaktivitaeten nach erfolgreicher Bestellung und Zahlung. Nach erfolgreicher Zahlung startet Fulfillment-Planung.; FulfillmentPlanner erzeugt naechste Schritte.
notification-domain Bounded Context Kapselt Benachrichtigungsvorlagen und die fachliche Entscheidung, welche Nachricht wann versendet werden soll. Ein Event wie OrderPlaced loest Benachrichtigung aus.; Template erzeugt fachlichen Inhalt.
order-application Use-Case-Schicht Orchestriert den fachlichen Bestellablauf zwischen Domain-Modulen, Ports, Transaktionen und Ergebnisobjekten. REST oder Quarkus Resource sendet PlaceOrderCommand.; PlaceOrderService prueft Regeln und erzeugt Order.
integration-outbox Integration / Reliability Macht Event-Publishing robust, indem fachliche Aenderung und Event-Auslieferungsabsicht getrennt aber nachvollziehbar behandelt werden. Domain erzeugt Event.; Application speichert Aggregate und OutboxRecord in einer Transaktion.
adapters-rest-spring Inbound Adapter Stellt HTTP-Endpunkte bereit und uebersetzt Web-Requests in Use-Case-Commands. Client sendet HTTP Request.; OrderRestController validiert und baut Command.
adapters-persistence-jpa Outbound Adapter Implementiert Persistenz fuer Orders und Outbox, ohne JPA in die Domain eindringen zu lassen. Application ruft OrderRepository.; JpaOrderRepositoryAdapter mappt Domain auf Entity.
adapters-messaging-kafka Outbound Messaging Adapter Publiziert Integrationsereignisse nach Kafka und schuetzt Konsumenten gegen doppelte Verarbeitung. OutboxRelay liefert Record an Publisher.; KafkaEventPublisher sendet Nachricht.
adapters-legacy-acl Legacy Integration Schuetzt moderne Domain vor altem SOAP-/Legacy-Modell durch eine Anti-Corruption-Layer. Application braucht Legacy-Daten.; LegacyOrderGateway ruft SOAP Client.
app-spring-boot Runtime Composition Startet die Spring-Boot-Variante und verdrahtet REST, Persistenz, Messaging, Security und Observability. Spring Boot startet Application Context.; UseCaseConfiguration verbindet Ports mit Adaptern.
app-quarkus Alternative Runtime Zeigt dieselben Use Cases in einer Quarkus/Jakarta-Runtime, um Framework-Austauschbarkeit der Architektur zu demonstrieren. Quarkus startet Resource.; InMemoryQuarkusWiring liefert Use-Case-Instanzen.
architecture-tests Qualitaets-Gate Prueft Architekturregeln automatisiert, damit Modulgrenzen und Pattern-Markierungen nicht nur Dokumentation bleiben. Maven test/verify fuehrt Architecture Tests aus.; LayerRulesTest prueft Abhaengigkeitsrichtung.

Lese-Reihenfolge

  1. shared-kernel fuer Grundtypen.
  2. order-domain fuer fachlichen Kern.
  3. order-application fuer Use-Case-Ablauf.
  4. adapters-rest-spring und adapters-persistence-jpa fuer technische Umsetzung.
  5. integration-outbox und adapters-messaging-kafka fuer robuste Events.
  6. app-spring-boot oder app-quarkus fuer Laufzeit.
  7. architecture-tests fuer automatische Regeln.

Entwurfsmuster im Ablauf

  • Aggregate Root: Order schuetzt Konsistenz.
  • Command Pattern: PlaceOrderCommand transportiert den Wunsch, eine Bestellung anzulegen.
  • Application Service: PlaceOrderService orchestriert, aber enthaelt keine Infrastrukturdetails.
  • Ports and Adapters: Use Cases kennen nur Ports; Adapter implementieren Technik.
  • Transactional Outbox: Domain-Aenderung und Event-Auslieferung werden robust gekoppelt.
  • Saga: Mehrschrittiger Zahlungs-/Fulfillment-Prozess wird explizit koordiniert.
  • Anti-Corruption Layer: Legacy-Modelle bleiben ausserhalb der modernen Domain.
  • Architecture Fitness Function: ArchUnit schuetzt Regeln im Build.

Stand 2026-07-07. Markdown und HTML synchron erzeugt.

⌂ Cockpit