{"id":703,"date":"2026-06-27T23:34:10","date_gmt":"2026-06-27T22:34:10","guid":{"rendered":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=703"},"modified":"2026-07-07T23:34:43","modified_gmt":"2026-07-07T22:34:43","slug":"spring-modulith-2-modul-architektur-mit-verifikation-und-event-getriebenen-modulen","status":"publish","type":"post","link":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=703","title":{"rendered":"Spring Modulith 2 \u2013 Modul-Architektur mit Verifikation und Event-getriebenen Modulen"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Je l\u00e4nger eine Spring-Boot-Anwendung lebt, desto gr\u00f6\u00dfer wird die Gefahr des \u201eBig Ball of Mud&#8220;: Services rufen wild andere Services auf, Zyklen entstehen, und aus dem sauberen Monolithen wird ein Wartungs-Albtraum. Spring Modulith 2 adressiert genau dieses Problem: Es strukturiert deine Anwendung in logische Module, erzwingt deren Grenzen und bereitet den Weg f\u00fcr eine eventuelle Microservice-Extraktion \u2014 alles ohne das Framework zu wechseln.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Was ist Spring Modulith?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring Modulith (aktuell&nbsp;<strong>2.1.0<\/strong>, f\u00fcr Spring Boot 4.1+) verpackt bew\u00e4hrte Architektur-Patterns in Spring-Boot-nativer Form:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Package-basierte Module<\/strong>\u00a0\u2014 Jedes Modul ist ein eigenes Package mit API (\u00f6ffentlich) und\u00a0<code>internal<\/code>-Subpackage (privat)<\/li>\n\n\n\n<li><strong>Verifikations-Tests<\/strong>\u00a0\u2014 Pr\u00fcfen Einhaltung von Modulgrenzen zur Build-Zeit via ArchUnit<\/li>\n\n\n\n<li><strong>Event-Publikations-Registry<\/strong>\u00a0\u2014 Transaktionale Events mit Wiederholungslogik<\/li>\n\n\n\n<li><strong>Dokumentation<\/strong>\u00a0\u2014 Generiert C4- und UML-Diagramme automatisch<\/li>\n\n\n\n<li><strong><code>@ApplicationModuleTest<\/code><\/strong>\u00a0\u2014 Testet Module in Isolation mit dem Scenario-API<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Projekt-Struktur<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Eine typische Modulith-Anwendung:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">src\/main\/java\/com\/shop\/\n\u251c\u2500\u2500 Application.java               <span class=\"hljs-comment\">\/\/ @Modulithic<\/span>\n\u251c\u2500\u2500 order\/\n\u2502   \u251c\u2500\u2500 package-info.java          <span class=\"hljs-comment\">\/\/ @ApplicationModule<\/span>\n\u2502   \u251c\u2500\u2500 OrderManagement.java       <span class=\"hljs-comment\">\/\/ \u00f6ffentliche API<\/span>\n\u2502   \u251c\u2500\u2500 OrderCompleted.java        <span class=\"hljs-comment\">\/\/ Domain-Event<\/span>\n\u2502   \u2514\u2500\u2500 internal\/\n\u2502       \u2514\u2500\u2500 OrderInternal.java     <span class=\"hljs-comment\">\/\/ privat, nur im order-Modul nutzbar<\/span>\n\u2514\u2500\u2500 inventory\/\n    \u251c\u2500\u2500 package-info.java\n    \u2514\u2500\u2500 InventoryManagement.java   <span class=\"hljs-comment\">\/\/ h\u00f6rt auf OrderCompleted<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Setup<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependencyManagement<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependencies<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.springframework.modulith<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>spring-modulith-bom<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">version<\/span>&gt;<\/span>2.1.0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">version<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">type<\/span>&gt;<\/span>pom<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">type<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">scope<\/span>&gt;<\/span>import<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">scope<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependencies<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependencyManagement<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependencies<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.springframework.modulith<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>spring-modulith-starter-core<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.springframework.modulith<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>spring-modulith-starter-jpa<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.springframework.modulith<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>spring-modulith-starter-test<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">scope<\/span>&gt;<\/span>test<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">scope<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependencies<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Die&nbsp;<code>@Modulithic<\/code>-Annotation auf der Application-Klasse aktiviert das Modulsystem:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> org.springframework.modulith.Modulithic;\n\n@Modulithic\n@SpringBootApplication\npublic <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Application<\/span> <\/span>{\n    public <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> main(<span class=\"hljs-built_in\">String<\/span>&#91;] args) {\n        SpringApplication.run(Application.class, args);\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Module definieren und Abh\u00e4ngigkeiten deklarieren<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>package-info.java<\/code>&nbsp;f\u00fcr jedes Modul:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">&lt;em&gt;<span class=\"hljs-comment\">\/\/ com\/shop\/order\/package-info.java&lt;\/em&gt;<\/span>\n@org.springframework.modulith.ApplicationModule(\n    displayName = <span class=\"hljs-string\">\"Bestellungen\"<\/span>,\n    allowedDependencies = <span class=\"hljs-string\">\"inventory\"<\/span>\n)\npackage com.shop.order;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ com\/shop\/inventory\/package-info.java<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\npackage com.shop.inventory;\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ keine allowedDependencies \u2192 darf auf alle exponierten APIs zugreifen<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Events zwischen Modulen<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Module kommunizieren ausschlie\u00dflich via Spring Application Events:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">&lt;em&gt;<span class=\"hljs-comment\">\/\/ Im order-Modul: Event publizieren&lt;\/em&gt;<\/span>\npackage com.shop.order;\n\nimport org.springframework.context.ApplicationEventPublisher;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\n@Service\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">OrderManagement<\/span> <\/span>{\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> ApplicationEventPublisher events;\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> OrderRepository orders;\n\n    <span class=\"hljs-keyword\">public<\/span> OrderManagement(ApplicationEventPublisher events,\n                           OrderRepository orders) {\n        this.events = events;\n        this.orders = orders;\n    }\n\n    @Transactional\n    <span class=\"hljs-keyword\">public<\/span> void complete(Long orderId) {\n        Order order = orders.findById(orderId).orElseThrow();\n        order.markCompleted();\n        orders.save(order);\n        events.publishEvent(<span class=\"hljs-keyword\">new<\/span> OrderCompleted(order.getId()));\n    }\n}\n\n<span class=\"hljs-keyword\">public<\/span> record OrderCompleted(Long orderId) {}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">&lt;em&gt;<span class=\"hljs-comment\">\/\/ Im inventory-Modul: Event empfangen&lt;\/em&gt;<\/span>\npackage com.shop.inventory;\n\n<span class=\"hljs-keyword\">import<\/span> com.shop.order.OrderCompleted;\n<span class=\"hljs-keyword\">import<\/span> org.springframework.modulith.ApplicationModuleListener;\n<span class=\"hljs-keyword\">import<\/span> org.springframework.stereotype.Component;\n\n@Component\npublic <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">InventoryManagement<\/span> <\/span>{\n\n    @ApplicationModuleListener\n    <span class=\"hljs-keyword\">void<\/span> on(OrderCompleted event) {\n        &lt;em&gt;<span class=\"hljs-comment\">\/\/ L\u00e4uft asynchron, in eigener Transaktion,&lt;\/em&gt;<\/span>\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ erst nachdem die Original-Transaktion committed wurde<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n        updateStockForOrder(event.orderId());\n    }\n\n    private <span class=\"hljs-keyword\">void<\/span> updateStockForOrder(Long orderId) {\n        &lt;em&gt;<span class=\"hljs-comment\">\/\/ Bestand reduzieren&lt;\/em&gt;<\/span>\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><code>@ApplicationModuleListener<\/code>&nbsp;ist ein Shortcut f\u00fcr&nbsp;<code>@Async<\/code>&nbsp;+&nbsp;<code>@Transactional(propagation = REQUIRES_NEW)<\/code>&nbsp;+&nbsp;<code>@TransactionalEventListener<\/code>&nbsp;\u2014 perfekt f\u00fcr lose gekoppelte Module.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Modul-Verifikationstests<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring Modulith generiert w\u00e4hrend des Builds automatisch Verifikationen. F\u00fcr eigene, explizite Tests:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> org.junit.jupiter.api.Test;\n<span class=\"hljs-keyword\">import<\/span> org.springframework.modulith.core.ApplicationModules;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">ModularityTests<\/span> <\/span>{\n\n    ApplicationModules modules = ApplicationModules.of(Application.class);\n\n    @Test\n    <span class=\"hljs-keyword\">void<\/span> verifyModularity() {\n        modules.verify();\n    }\n\n    @Test\n    <span class=\"hljs-keyword\">void<\/span> noCycles() {\n        modules.detectViolations().throwIfPresent();\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Das erkennt:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Zyklen zwischen Modulen<\/li>\n\n\n\n<li>Zugriffe auf\u00a0<code>*.internal.*<\/code>-Packages von au\u00dfen<\/li>\n\n\n\n<li>Verst\u00f6\u00dfe gegen\u00a0<code>allowedDependencies<\/code><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Modul-Isolierte Integrationstests mit @ApplicationModuleTest<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">package com.shop.order;\n\n<span class=\"hljs-keyword\">import<\/span> org.junit.jupiter.api.Test;\n<span class=\"hljs-keyword\">import<\/span> org.springframework.modulith.test.ApplicationModuleTest;\n<span class=\"hljs-keyword\">import<\/span> org.springframework.modulith.test.PublishedEvents;\n<span class=\"hljs-keyword\">import<\/span> org.springframework.modulith.test.Scenario;\n<span class=\"hljs-keyword\">import<\/span> org.springframework.beans.factory.annotation.Autowired;\n\n@ApplicationModuleTest  &lt;em&gt;<span class=\"hljs-comment\">\/\/ Bootet nur das order-Modul&lt;\/em&gt;<\/span>\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">OrderIntegrationTests<\/span> <\/span>{\n\n    @Autowired OrderManagement orders;\n\n    @Test\n    <span class=\"hljs-keyword\">void<\/span> completingOrderPublishesEvent(PublishedEvents events) {\n        orders.complete(<span class=\"hljs-number\">1<\/span>L);\n\n        events.ofType(OrderCompleted.class)\n              .matching(e -&gt; e.orderId().equals(<span class=\"hljs-number\">1<\/span>L))\n              .hasSize(<span class=\"hljs-number\">1<\/span>);\n    }\n\n    @Test\n    <span class=\"hljs-keyword\">void<\/span> asyncScenarioExample(Scenario scenario) {\n        scenario.publish(<span class=\"hljs-keyword\">new<\/span> OrderCompleted(<span class=\"hljs-number\">42<\/span>L))\n                .andWaitForEventOfType(StockUpdated.class)\n                .matching(e -&gt; e.orderId().equals(<span class=\"hljs-number\">42<\/span>L))\n                .toArriveAndVerify(event -&gt; {\n                    assertThat(event.newStockLevel()).isGreaterThan(<span class=\"hljs-number\">0<\/span>);\n                });\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Der&nbsp;<code>Scenario<\/code>-API ist das Herzst\u00fcck asynchroner Modul-Tests:&nbsp;<code>publish()<\/code>\/<code>stimulate()<\/code>&nbsp;\u2192 Event erwarten \u2192 Zustands\u00e4nderung verifizieren.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Automatische Dokumentation<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> org.junit.jupiter.api.Test;\n<span class=\"hljs-keyword\">import<\/span> org.springframework.modulith.docs.Documenter;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">DocumentationTests<\/span> <\/span>{\n\n    ApplicationModules modules = ApplicationModules.of(Application.class);\n\n    @Test\n    <span class=\"hljs-keyword\">void<\/span> generateDocs() {\n        <span class=\"hljs-keyword\">new<\/span> Documenter(modules)\n            .writeModulesAsPlantUml()          &lt;em&gt;<span class=\"hljs-comment\">\/\/ System C4 Diagramm&lt;\/em&gt;<\/span>\n            .writeIndividualModulesAsPlantUml() &lt;em&gt;<span class=\"hljs-comment\">\/\/ Pro-Modul Diagramm&lt;\/em&gt;<\/span>\n            .writeModuleCanvases()              &lt;em&gt;<span class=\"hljs-comment\">\/\/ Tabellarische Modul-\u00dcbersichten&lt;\/em&gt;<\/span>\n            .writeAggregatingDocument();        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Alles-in-einem AsciiDoc<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Die Dateien landen in&nbsp;<code>target\/spring-modulith-docs\/<\/code>&nbsp;und enthalten C4-Diagramme (PlantUML), Modul-Canvases (Spring Beans, Events, Properties) und ein aggregierendes AsciiDoc.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Der Weg zu Microservices<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring Modulith unterst\u00fctzt den schrittweisen \u00dcbergang zum Microservice:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Heute:<\/strong>\u00a0Monolith mit Modul-Grenzen und internen Events<\/li>\n\n\n\n<li><strong>Morgen:<\/strong>\u00a0Events mit\u00a0<code>@Externalized<\/code>\u00a0annotieren \u2192 Kafka\/AMQP<code>@Externalized(\"order-completed::#{#this.orderId()}\") public record OrderCompleted(Long orderId) {}<\/code><\/li>\n\n\n\n<li><strong>\u00dcbermorgen:<\/strong>\u00a0Modul als eigener Service extrahieren, Events vom Broker konsumieren<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Keine Code-\u00c4nderung innerhalb des Moduls n\u00f6tig.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring Modulith 2 ist kein neues Framework \u2014 es ist ein Architektur-Werkzeugkasten f\u00fcr Spring Boot, der saubere Modulgrenzen zur Build-Zeit erzwingt und asynchrone Event-Kommunikation f\u00f6rdert. Die automatische C4-Dokumentation ist ein netter Bonus, der gerade in wachsenden Teams Gold wert ist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr jedes Spring-Boot-Projekt mit mehr als 2 Modulen: Setzt Spring Modulith ein, bevor der Monolith unwartbar wird. Euer zuk\u00fcnftiges Ich wird es euch danken.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Je l\u00e4nger eine Spring-Boot-Anwendung lebt, desto gr\u00f6\u00dfer wird die Gefahr des \u201eBig Ball of Mud&#8220;: Services rufen wild andere Services auf, Zyklen entstehen, und aus dem sauberen Monolithen wird ein Wartungs-Albtraum. Spring Modulith 2 adressiert genau dieses Problem: Es strukturiert deine Anwendung in logische Module, erzwingt deren Grenzen und bereitet den Weg f\u00fcr eine eventuelle [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-703","post","type-post","status-publish","format-standard","hentry","category-spring"],"_links":{"self":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/703","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=703"}],"version-history":[{"count":1,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/703\/revisions"}],"predecessor-version":[{"id":704,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/703\/revisions\/704"}],"wp:attachment":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=703"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=703"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=703"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}