From 36ec890de881faa406dbcdaeae82d254fb35c82f Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Fri, 19 Apr 2024 17:32:19 +0200 Subject: [PATCH] GH-550 - Rearrange sections in reference doc. The exclusion of types from the Application Modules model is now described in the section about the ApplicationModules type already. That general section is now located before the discussion of simple and advanced modules. The verification section now mentions the behavior for open modules as well. --- .../modules/ROOT/pages/fundamentals.adoc | 158 +++++++++++------- .../modules/ROOT/pages/verification.adoc | 31 +--- 2 files changed, 98 insertions(+), 91 deletions(-) diff --git a/src/docs/antora/modules/ROOT/pages/fundamentals.adoc b/src/docs/antora/modules/ROOT/pages/fundamentals.adoc index c2aa9c55..545eb8d0 100644 --- a/src/docs/antora/modules/ROOT/pages/fundamentals.adoc +++ b/src/docs/antora/modules/ROOT/pages/fundamentals.adoc @@ -1,12 +1,14 @@ [[fundamentals]] = Fundamentals +:toc: +:toclevels: 3 Spring Modulith supports developers implementing logical modules in Spring Boot applications. It allows them to apply structural validation, document the module arrangement, run integration tests for individual modules, observe the modules' interaction at runtime, and generally implement module interaction in a loosely coupled way. This section will discuss the fundamental concepts that developers need to understand before diving into the technical support. [[modules]] -== Application modules +== Application Modules In a Spring Boot application, an application module is a unit of functionality that consists of the following parts: @@ -17,6 +19,100 @@ In a Spring Boot application, an application module is a unit of functionality t Spring Moduliths provides different ways of expressing modules within Spring Boot applications, primarily differing in the level of complexity involved in the overall arrangement. This allows developers to start simple and naturally move to more sophisticated means as and if needed. +[[modules.application-modules]] +=== The `ApplicationModules` Type + +Spring Moduliths allows to inspect a codebase to derive an application module model based on the given arrangement and optional configuration. +The `spring-modulith-core` artifact contains `ApplicationModules` that can be pointed to a Spring Boot application class: + +.Creating an application module model +[tabs] +====== +Java:: ++ +[source, java, role="primary"] +---- +var modules = ApplicationModules.of(Application.class); +---- +Kotlin:: ++ +[source, kotlin, role="secondary"] +---- +var modules = ApplicationModules.of(Application::class) +---- +====== +The `modules` will contain an in-memory representation of the application module arrangement derived from the codebase. +Which parts of that will be detected as a module depends on the Java package structure underneath the package the class pointed to resides in. +Find out more about the arrangement expected by default in xref:fundamentals.adoc#modules.simple[]. +Advanced arrangements and customization options are described in xref:fundamentals.adoc#modules.advanced[] and + +To get an impression of what the analyzed arrangement looks like, we can just write the individual modules contained in the overall model to the console: + +.Writing the application module arrangement to the console +[tabs] +====== +Java:: ++ +[source, java, role="primary"] +---- +modules.forEach(System.out::println); +---- +Kotlin:: ++ +[source, kotlin, role="secondary"] +---- +modules.forEach(println(it)) +---- +====== +.The console output of our application module arrangement +[source] +---- +## example.inventory ## +> Logical name: inventory +> Base package: example.inventory +> Spring beans: + + ….InventoryManagement + o ….SomeInternalComponent + +## example.order ## +> Logical name: order +> Base package: example.order +> Spring beans: + + ….OrderManagement + + ….internal.SomeInternalComponent +---- + +Note how each module is listed, the contained Spring components are identified, and the respective visibility is rendered, too. + +[[modules.excluding-packages]] +==== Excluding Packages + +In case you would like to exclude certain Java classes or full packages from the application module inspection, you can do so with: + +[tabs] +====== +Java:: ++ +[source, java, role="primary"] +---- +ApplicationModules.of(Application.class, JavaClass.Predicates.resideInAPackage("com.example.db")).verify(); +---- +Kotlin:: ++ +[source, kotlin, role="secondary"] +---- +ApplicationModules.of(Application::class, JavaClass.Predicates.resideInAPackage("com.example.db")).verify() +---- +====== + +Additional examples of exclusions: + +* `com.example.db` -- Matches all files in the given package `com.example.db`. +* `com.example.db..` -- Matches all files in the given package (`com.example.db`) and all sub-packages (`com.example.db.a` or `com.example.db.b.c`). +* `..example..` -- Matches `a.example`, `a.example.b` or `a.b.example.c.d`, but not `a.exam.b` + +Full details about possible matchers can be found in the JavaDoc of ArchUnit https://github.com/TNG/ArchUnit/blob/main/archunit/src/main/java/com/tngtech/archunit/core/domain/PackageMatcher.java[`PackageMatcher`]. + [[modules.simple]] === Simple Application Modules @@ -145,66 +241,6 @@ class ModuleMetadata {} In this case code within the __inventory__ module was only allowed to refer to code in the __order__ module (and code not assigned to any module in the first place). Find out about how to monitor that in xref:verification.adoc[Verifying Application Module Structure]. -[[modules.application-modules]] -=== The `ApplicationModules` Type - -Spring Moduliths allows to inspect a codebase to derive an application module model based on the given arrangement and optional configuration. -The `spring-modulith-core` artifact contains `ApplicationModules` that can be pointed to a Spring Boot application class: - -.Creating an application module model -[tabs] -====== -Java:: -+ -[source, java, role="primary"] ----- -var modules = ApplicationModules.of(Application.class); ----- -Kotlin:: -+ -[source, kotlin, role="secondary"] ----- -var modules = ApplicationModules.of(Application::class) ----- -====== -To get an impression of what the analyzed arrangement looks like, we can just write the individual modules contained in the overall model to the console: - -.Writing the application module arrangement to the console -[tabs] -====== -Java:: -+ -[source, java, role="primary"] ----- -modules.forEach(System.out::println); ----- -Kotlin:: -+ -[source, kotlin, role="secondary"] ----- -modules.forEach(println(it)) ----- -====== -.The console output of our application module arrangement -[source] ----- -## example.inventory ## -> Logical name: inventory -> Base package: example.inventory -> Spring beans: - + ….InventoryManagement - o ….SomeInternalComponent - -## example.order ## -> Logical name: order -> Base package: example.order -> Spring beans: - + ….OrderManagement - + ….internal.SomeInternalComponent ----- - -Note how each module is listed, the contained Spring components are identified, and the respective visibility is rendered, too. - [[modules.named-interfaces]] === Named Interfaces diff --git a/src/docs/antora/modules/ROOT/pages/verification.adoc b/src/docs/antora/modules/ROOT/pages/verification.adoc index cd6f7cd4..52b3fea2 100644 --- a/src/docs/antora/modules/ROOT/pages/verification.adoc +++ b/src/docs/antora/modules/ROOT/pages/verification.adoc @@ -24,38 +24,9 @@ The verification includes the following rules: * _No cycles on the application module level_ -- the dependencies between modules have to form a directed acyclic graph. * _Efferent module access via API packages only_ -- all references to types that reside in application module internal packages are rejected. See xref:fundamentals.adoc#modules.advanced[Advanced Application Modules] for details. +Dependencies into internals of xref:fundamentals.adoc#modules.advanced.open[Open Application Modules] are allowed. * _Explicitly allowed application module dependencies only_ (optional) -- an application module can optionally define allowed dependencies via `@ApplicationModule(allowedDependencies = …)`. If those are configured, dependencies to other application modules are rejected. See xref:fundamentals.adoc#modules.explicit-dependencies[Explicit Application Module Dependencies] and xref:fundamentals.adoc#modules.named-interfaces[Named Interfaces] for details. Spring Modulith optionally integrates with the jMolecules ArchUnit library and, if present, automatically triggers its Domain-Driven Design verification rules described https://github.com/xmolecules/jmolecules-integrations/tree/main/jmolecules-archunit[here]. - -[[excluding-packages]] -== Excluding Packages - -In case you would like to exclude certain Java classes or full packages from the application module inspection, you can do so with: - -[tabs] -====== -Java:: -+ -[source, java, role="primary"] ----- -ApplicationModules.of(Application.class, JavaClass.Predicates.resideInAPackage("com.example.db")).verify(); ----- -Kotlin:: -+ -[source, kotlin, role="secondary"] ----- -ApplicationModules.of(Application::class, JavaClass.Predicates.resideInAPackage("com.example.db")).verify() ----- -====== - -Additional examples of exclusions: - -* `com.example.db` -- Matches all files in the given package `com.example.db`. -* `com.example.db..` -- Matches all files in the given package (`com.example.db`) and all sub-packages (`com.example.db.a` or `com.example.db.b.c`). -* `..example..` -- Matches `a.example`, `a.example.b` or `a.b.example.c.d`, but not `a.exam.b` - -Full details about possible matchers can be found in the JavaDoc of ArchUnit https://github.com/TNG/ArchUnit/blob/main/archunit/src/main/java/com/tngtech/archunit/core/domain/PackageMatcher.java[`PackageMatcher`]. -