### Basic Integration Test Setup with @DataJpaTest
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Demonstrates a basic JUnit 5 integration test setup using `@DataJpaTest` and `@ModuleSlicing` for testing a specific module's repository.
```java
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
import org.springframework.modulith.test.ModuleSlicing;
@ModuleSlicing
@DataJpaTest
class SomeModuleRepositoryIntegrationTests {
@Autowired SomeRepository repository;
@Test
void someTest() { … }
}
```
--------------------------------
### Example Response for Application Modules Actuator
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
An example JSON response from the application modules actuator endpoint.
```APIDOC
## Example Response
### Application Modules Actuator
```json
{
"a": {
"basePackage": "example.a",
"displayName": "A",
"dependencies": []
},
"b": {
"basePackage": "example.b",
"displayName": "B",
"dependencies": [ {
"target": "a",
"types": [ "EVENT_LISTENER", "USES_COMPONENT" ]
} ]
}
}
```
```
--------------------------------
### Defining a Stimulus: Event Publication
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Illustrates how to start a `Scenario` by publishing an application event. This action is performed within a transaction callback.
```java
// Start with an event publication
scenario.publish(new MyApplicationEvent(…)).…
```
```kotlin
// Start with an event publication
scenario.publish(MyApplicationEvent(…)).…
```
--------------------------------
### Example Application Modules Actuator Response
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
This JSON structure represents the response from the application modules actuator, detailing module base packages, display names, and dependencies.
```json
{
"a": {
"basePackage": "example.a",
"displayName": "A",
"dependencies": []
},
"b": {
"basePackage": "example.b",
"displayName": "B",
"dependencies": [ {
"target": "a",
"types": [ "EVENT_LISTENER", "USES_COMPONENT" ]
} ]
}
}
```
--------------------------------
### Service with Direct Dependency
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/events.adoc
Example of a service class with a direct dependency on another service, leading to tight coupling.
```java
@Service
@RequiredArgsConstructor
public class OrderManagement {
private final InventoryManagement inventory;
@Transactional
public void complete(Order order) {
// State transition on the order aggregate go here
// Invoke related functionality
inventory.updateStockFor(order);
}
}
```
```kotlin
@Service
class OrderManagement(val inventory: InventoryManagement) {
@Transactional
fun complete(order: Order) {
inventory.updateStockFor(order)
}
}
```
--------------------------------
### Observability Dependency Setup
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
Add the necessary runtime dependency to enable Spring Modulith's observability support. For customizing metrics, include the API artifact as well.
```APIDOC
## Dependency Management
### Maven
```xml
org.springframework.modulith
spring-modulith-observability-core
{projectVersion}
runtime
```
### Gradle
```gradle
dependencies {
runtimeOnly 'org.springframework.modulith:spring-modulith-observability-core:{projectVersion}'
}
```
For compile-time customization of metrics:
```xml
org.springframework.modulith
spring-modulith-observability-api
{projectVersion}
compile
```
```gradle
dependencies {
compileOnly 'org.springframework.modulith:spring-modulith-observability-api:{projectVersion}'
}
```
```
--------------------------------
### Access Modulith Actuator HTTP Resource
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
Example response from the actuator endpoint showing the modulith resource.
```json
GET http://localhost:8080/actuator
{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"health-path": {
"href": "http://localhost:8080/actuator/health/{*path}",
"templated": true
},
"health": {
"href": "http://localhost:8080/actuator/health",
"templated": false
},
"modulith": { <1>
"href": "http://localhost:8080/actuator/modulith",
"templated": false
}
}
}
```
--------------------------------
### Create Application Module Model (Java)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Use `ApplicationModules.of()` to create an in-memory representation of your application's module arrangement. Point it to your Spring Boot application class to start the analysis.
```java
var modules = ApplicationModules.of(Application.class);
```
--------------------------------
### Transactional Event Listener with @Async
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/events.adoc
Example of a transactional event listener using @Async and @Transactional(propagation = Propagation.REQUIRES_NEW).
```kotlin
@Component
class InventoryManagement {
@Async
@Transactional(propagation = Propagation.REQUIRES_NEW)
@TransactionalEventListener
fun on(event: OrderCompleted) { /* … */ }
}
```
--------------------------------
### Implement Custom ApplicationModuleDetectionStrategy (Kotlin)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Provide a custom implementation of `ApplicationModuleDetectionStrategy` to define your own module detection logic. This Kotlin example shows the basic structure.
```kotlin
package example
class CustomApplicationModuleDetectionStrategy : ApplicationModuleDetectionStrategy {
override fun getModuleBasePackages(basePackage: JavaPackage): Stream {
// Your module detection goes here
}
}
```
--------------------------------
### Implement Custom ApplicationModuleDetectionStrategy (Java)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Provide a custom implementation of `ApplicationModuleDetectionStrategy` to define your own module detection logic. This Java example shows the basic structure.
```java
package example;
class CustomApplicationModuleDetectionStrategy implements ApplicationModuleDetectionStrategy {
@Override
public Stream getModuleBasePackages(JavaPackage basePackage) {
// Your module detection goes here
}
}
```
--------------------------------
### Register ScenarioCustomizer in Kotlin
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Registers a ScenarioCustomizer as a JUnit extension for global scenario customization in Kotlin. This ensures uniform test setup across a test class.
```kotlin
@ExtendWith(MyCustomizer::class)
class MyTests {
@Test
fun myTestCase(scenario: Scenario) {
// scenario will be pre-customized with logic defined in MyCustomizer
}
class MyCustomizer : ScenarioCustomizer {
override fun getDefaultCustomizer(method: Method, context: ApplicationContext): UnaryOperator {
return UnaryOperator { conditionFactory -> … }
}
}
}
```
--------------------------------
### Prepare a release with Maven
Source: https://github.com/spring-projects/spring-modulith/blob/main/etc/build-and-releases.adoc
Execute this command on the version branch to prepare a release, specifying the version, development version, and SCM commit comments.
```bash
./mvnw release:prepare \
-Pprepare-release \
-DreleaseVersion="${version}" \
-DdevelopmentVersion="${devVersion}" \
-DscmReleaseCommitComment="${ticketId} - Release version ${version}." \
-DscmDevelopmentCommitComment="${ticketId} - Prepare next development iteration." \
-Dtag="${version}"
```
--------------------------------
### Spring Modulith Starter Modules
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/appendix.adoc
Overview of available Spring Modulith starter POMs and their included dependencies.
```APIDOC
## Starter Modules
- **spring-modulith-starter-core**: Includes core, api, apt, moments, and runtime support.
- **spring-modulith-starter-insight**: Includes actuator and observability support.
- **spring-modulith-starter-jdbc**: Includes core and JDBC event support.
- **spring-modulith-starter-jpa**: Includes core and JPA event support.
- **spring-modulith-starter-mongodb**: Includes core and MongoDB event support.
- **spring-modulith-starter-neo4j**: Includes core and Neo4j event support.
- **spring-modulith-starter-test**: Includes documentation and testing utilities.
```
--------------------------------
### Print Application Module Arrangement (Java)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Iterate over the `ApplicationModules` object and print each module's details to the console using `forEach` and `System.out::println`.
```java
modules.forEach(System.out::println);
```
--------------------------------
### Print Application Module Arrangement (Kotlin)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Use the `forEach` lambda to print the details of each module within the `ApplicationModules` object to the console.
```kotlin
modules.forEach { println(it) }
```
--------------------------------
### Enable Spring Modulith Insight Starter
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
Add the Insight starter to enable both actuator and observability support for application modules.
```xml
org.springframework.modulith
spring-modulith-starter-insight
{projectVersion}
runtime
```
```gradle
dependencies {
runtimeOnly 'org.springframework.modulith:spring-modulith-starter-insight:{projectVersion}'
}
```
--------------------------------
### Declare Spring Modulith Namastack Starter
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/events.adoc
Add the Namastack starter dependency to enable advanced outbox features for relational databases.
```xml
org.springframework.modulith
spring-modulith-starter-namastack
```
```gradle
dependencies {
implementation 'org.springframework.modulith:spring-modulith-starter-namastack'
}
```
--------------------------------
### Build Spring Modulith Project
Source: https://github.com/spring-projects/spring-modulith/blob/main/readme.adoc
Command to compile, test, and build the project using the Maven wrapper.
```bash
./mvnw -B
```
--------------------------------
### Application Module Listener Shortcut
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/events.adoc
Demonstrates using @ApplicationModuleListener as a shortcut for declaring module integration via events.
```java
@Component
class InventoryManagement {
@ApplicationModuleListener
void on(OrderCompleted event) { /* … */ }
}
```
```kotlin
@Component
class InventoryManagement {
@ApplicationModuleListener
fun on(event: OrderCompleted) { /* … */ }
}
```
--------------------------------
### Implement Custom Application Module Initializer (Java)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/runtime.adoc
Implement the `ApplicationModuleInitializer` interface in Java to define custom initialization logic for a module. The execution order follows the module dependency structure.
```java
@Component
class MyInitializer implements ApplicationModuleInitializer {
@Override
public void initialize() {
// Initialization code goes here
}
}
```
--------------------------------
### Configure Traditional UML Component Diagrams
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/documentation.adoc
Adjust DiagramOptions to switch from C4 to traditional UML style component diagrams.
```java
DiagramOptions.defaults()
```
--------------------------------
### Add Spring Modulith Test Starter
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Include the `spring-modulith-starter-test` dependency in your project to enable integration testing capabilities.
```xml
org.springframework.modulith
spring-modulith-starter-test
test
```
--------------------------------
### Implement Custom Application Module Initializer (Kotlin)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/runtime.adoc
Implement the `ApplicationModuleInitializer` interface in Kotlin to define custom initialization logic for a module. The execution order follows the module dependency structure.
```kotlin
@Component
class MyInitializer : ApplicationModuleInitializer {
override fun initialize() {
// Initialization code goes here
}
}
```
--------------------------------
### Verify Event Arrival
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Executes a scenario and defines assertions on the received event. Use this to confirm specific events are published and meet certain criteria.
```kotlin
….toArriveAndVerify(event -> …)
```
--------------------------------
### Expecting an Event with Matchers
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Shows how to define an expectation for a specific event type to be published as the result of a scenario, with optional matching criteria.
```java
….andWaitForEventOfType(SomeOtherEvent.class)
.matching(event -> …) // Use some predicate here
.…
```
```kotlin
….andWaitForEventOfType(SomeOtherEvent.class)
.matching(event -> …) // Use some predicate here
.…
```
--------------------------------
### Generate Documentation Snippets
Source: https://github.com/spring-projects/spring-modulith/blob/main/readme.adoc
Use the Documenter class to generate PlantUML diagrams from your application module model.
```java
class ApplicationTests {
@Test
void writeDocumentationSnippets() {
var modules = ApplicationModules.of(Application.class).verify(); <1>
new Documenter(modules) <2>
.writeModulesAsPlantUml()
.writeIndividualModulesAsPlantUml();
}
}
```
--------------------------------
### Define a Complete Scenario in Java
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Publishes an event, waits for another event of a specific type, matches it based on a condition, and verifies its arrival. This is for end-to-end event flow testing.
```java
scenario.publish(new MyApplicationEvent(…))
.andWaitForEventOfType(SomeOtherEvent.class)
.matching(event -> …)
.toArriveAndVerify(event -> …);
```
--------------------------------
### Create Application Module Model (Kotlin)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Use `ApplicationModules.of()` with the application class reference to create an in-memory model of your application's modules in Kotlin.
```kotlin
val modules = ApplicationModules.of(Application::class.java)
```
--------------------------------
### Verify Application Module Structure (Java)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/verification.adoc
Call `ApplicationModules.of(Application.class).verify()` to check if the code arrangement adheres to intended constraints. This is useful for enforcing architectural rules.
```java
ApplicationModules.of(Application.class).verify();
```
--------------------------------
### Generate Application Module Component Diagrams
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/documentation.adoc
Use the Documenter class to produce C4 component diagrams for the entire system or individual modules.
```java
class DocumentationTests {
ApplicationModules modules = ApplicationModules.of(Application.class);
@Test
void writeDocumentationSnippets() {
new Documenter(modules)
.writeModulesAsPlantUml()
.writeIndividualModulesAsPlantUml();
}
}
```
```kotlin
class DocumentationTests {
private val modules = ApplicationModules.of(Application::class.java)
@Test
fun writeDocumentationSnippets() {
Documenter(modules)
.writeModulesAsPlantUml()
.writeIndividualModulesAsPlantUml()
}
}
```
--------------------------------
### Observability Metrics - All Events
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
Details on the `module.events.published` metric and its low cardinality keys.
```APIDOC
## Observability Metrics
### The All Events Metric
- `module.events.published` – a counter summarizing all event publications.
#### Low Cardinality Keys
|===
|Name | Description
|`module.event.type`|Type of the emitted event.
|`module.identifier`|The identifier of the module.
|`module.name`|Name of the module.
|===
```
--------------------------------
### Generate Aggregating Document with Documenter (Kotlin)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/documentation.adoc
This Kotlin code snippet demonstrates how to generate an aggregating document using `Documenter.writeAggregatingDocument()`. It requires `ApplicationModules` to be initialized.
```kotlin
class DocumentationTests {
private val modules = ApplicationModules.of(Application::class.java)
@Test
fun writeDocumentationSnippets() {
Documenter(modules)
.writeAggregatingDocument()
}
}
```
--------------------------------
### Define a Complete Scenario in Kotlin
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Publishes an event, waits for another event of a specific type, matches it using a lambda, and verifies its arrival. This is the Kotlin equivalent for end-to-end event flow testing.
```kotlin
scenario.publish(new MyApplicationEvent(…))
.andWaitForEventOfType(SomeOtherEvent::class.java)
.matching { event -> … }
.toArriveAndVerify { event -> … }
```
--------------------------------
### Enable Spring Modulith Actuator Support
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
Add the actuator dependency and the Spring Boot actuator starter to expose module information.
```xml
org.springframework.modulith
spring-modulith-actuator
{projectVersion}
runtime
org.springframework.boot
spring-boot-starter-actuator
…
runtime
```
```gradle
dependencies {
runtimeOnly 'org.springframework.modulith:spring-modulith-actuator:{projectVersion}'
}
dependencies {
runtimeOnly 'org.springframework.boot:spring-boot-starter-actuator'
}
```
--------------------------------
### Clone Spring Modulith Repository
Source: https://github.com/spring-projects/spring-modulith/blob/main/readme.adoc
Commands to clone the source code repository.
```bash
git clone git@github.com:spring-projects/spring-modulith.git
cd spring-modulith
```
--------------------------------
### Configure Spring Modulith Dependencies
Source: https://github.com/spring-projects/spring-modulith/blob/main/readme.adoc
Add the BOM and test starter to your Maven project to enable Spring Modulith features.
```xml
org.springframework.modulith
spring-modulith-bom
2.0.5
import
pom
org.springframework.modulith
spring-modulith-starter-test
test
```
--------------------------------
### Customize Verification with VerificationOptions
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/verification.adoc
Configure custom verification rules, such as jMolecules Architecture rules, using `VerificationOptions`. This allows for fine-grained control over the verification process.
```java
var hexagonal = JMoleculesArchitectureRules.ensureHexagonal(VerificationDepth.STRICT);
var options = VerificationOptions.defaults().withAdditionalVerifications(hexagonal);
ApplicationModules.of(…).verify(options);
```
--------------------------------
### Declare Application Module as Open (Kotlin)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
In Kotlin, use the @ApplicationModule annotation with Type.OPEN on a ModuleMetadata class in the root package. This achieves the same effect as the Java package-info.java approach.
```kotlin
package example.inventory
import org.springframework.modulith.ApplicationModule
import org.springframework.modulith.PackageInfo
@ApplicationModule(
type = Type.OPEN
)
@PackageInfo
class ModuleMetadata {}
```
--------------------------------
### Verify Application Module Structure (Kotlin)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/verification.adoc
Use `ApplicationModules.of(Application::class.java).verify()` in Kotlin to ensure your application module structure follows defined rules. This method checks for architectural violations.
```kotlin
ApplicationModules.of(Application::class.java).verify()
```
--------------------------------
### Generate Aggregating Document with Documenter (Java)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/documentation.adoc
Use this Java code to generate an aggregating document by calling `Documenter.writeAggregatingDocument()`. Ensure you have initialized `ApplicationModules`.
```java
class DocumentationTests {
ApplicationModules modules = ApplicationModules.of(Application.class);
@Test
void writeDocumentationSnippets() {
new Documenter(modules)
.writeAggregatingDocument();
}
}
```
--------------------------------
### Generate Application Module Canvases
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/documentation.adoc
Uses the Documenter class to generate documentation canvases for application modules.
```java
class DocumentationTests {
ApplicationModules modules = ApplicationModules.of(Application.class);
@Test
void writeDocumentationSnippets() {
new Documenter(modules)
.writeModuleCanvases();
}
}
```
```kotlin
class DocumentationTests {
private val modules = ApplicationModules.of(Application::class.java)
@Test
fun writeDocumentationSnippets() {
Documenter(modules)
.writeModuleCanvases()
}
}
```
--------------------------------
### Executing the Scenario
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Provides the terminal operation to trigger the execution of the event-based `Scenario` and verify its outcome.
```java
// Executes the scenario
….toArrive(…)
```
--------------------------------
### Configure Diagram Style
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/documentation.adoc
Sets the diagram style to UML for module relationship visualization.
```java
.withStyle(DiagramStyle.UML);
```
```kotlin
DiagramOptions.defaults()
.withStyle(DiagramStyle.UML)
```
--------------------------------
### Observability Metrics - Individual Events
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
Details on the `module.events.published.$moduleIdentifier.$simpleEventTypeName` metric and its low cardinality keys.
```APIDOC
### The Individual Events Metric
- `module.events.published.$moduleIdentifier.$simpleEventTypeName` - a counter for the individual event that can be further enriched with domain-specific values.
#### Low Cardinality Keys
|===
|Name | Description
|`module.identifier`|The identifier of the module.
|`module.name`|Name of the module.
|===
```
--------------------------------
### Implement Custom ApplicationModuleSourceFactory
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Implement `ApplicationModuleSourceFactory` to define root packages for scanning, specify a detection strategy, and list explicit module base packages.
```java
package example;
public class CustomApplicationModuleSourceFactory implements ApplicationModuleSourceFactory {
@Override
public List getRootPackages() {
return List.of("com.acme.toscan");
}
@Override
public ApplicationModuleDetectionStrategy getApplicationModuleDetectionStrategy() {
return ApplicationModuleDetectionStrategy.explicitlyAnnotated();
}
@Override
public List getModuleBasePackages() {
return List.of("com.acme.module");
}
}
```
--------------------------------
### Render UML Component Diagrams
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/documentation.adoc
PlantUML configuration for rendering module relationships as component diagrams.
```plantuml
skinparam {
shadowing false
arrowColor #707070
actorBorderColor #707070
componentBorderColor #707070
rectangleBorderColor #707070
noteBackgroundColor #ffffff
noteBorderColor #707070
defaultTextAlignment center
wrapWidth 200
maxMessageSize 100
componentStyle uml1
}
package "Application" <> {
component 4 <> #dddddd [
com.acme.commerce.catalog
]
component 3 <> #dddddd [
com.acme.commerce.core
]
component 7 <> #dddddd [
com.acme.commerce.customer
]
component 5 <> #dddddd [
com.acme.commerce.inventory
]
component 6 <> #dddddd [
com.acme.commerce.order
]
}
4 .[#707070].> 3 : depends on
5 .[#707070].> 4 : uses
5 .[#707070].> 3 : uses
5 .[#707070].> 6 : uses
5 .[#707070].> 6 : listens to
6 .[#707070].> 4 : depends on
6 .[#707070].> 3 : depends on
6 .[#707070].> 7 : uses
```
```plantuml
skinparam {
shadowing false
arrowColor #707070
actorBorderColor #707070
componentBorderColor #707070
rectangleBorderColor #707070
noteBackgroundColor #ffffff
noteBorderColor #707070
defaultTextAlignment center
wrapWidth 200
maxMessageSize 100
componentStyle uml1
}
package "Application" <> {
component 4 <> #dddddd [
com.acme.commerce.catalog
]
component 3 <> #dddddd [
com.acme.commerce.core
]
component 7 <> #dddddd [
com.acme.commerce.customer
]
component 6 <> #dddddd [
com.acme.commerce.order
]
}
4 .[#707070].> 3 : depends on
6 .[#707070].> 4 : depends on
6 .[#707070].> 3 : depends on
6 .[#707070].> 7 : uses
```
--------------------------------
### Programmatically Configure Event Externalization
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/events.adoc
Customize event selection, mapping, headers, and routing keys using the EventExternalizationConfiguration API.
```java
@Configuration
class ExternalizationConfiguration {
@Bean
EventExternalizationConfiguration eventExternalizationConfiguration() {
return EventExternalizationConfiguration.externalizing() // <1>
.select(EventExternalizationConfiguration.annotatedAsExternalized()) // <2>
.mapping(SomeEvent.class, event -> …) // <3>
.headers(event -> …) // <4>
.routeKey(WithKeyProperty.class, WithKeyProperty::getKey) // <5>
.build();
}
}
```
```kotlin
@Configuration
class ExternalizationConfiguration {
@Bean
fun eventExternalizationConfiguration(): EventExternalizationConfiguration {
EventExternalizationConfiguration.externalizing() // <1>
.select(EventExternalizationConfiguration.annotatedAsExternalized()) // <2>
.mapping(SomeEvent::class.java) { event -> … } // <3>
.headers() { event -> … } // <4>
.routeKey(WithKeyProperty::class.java, WithKeyProperty::getKey) // <5>
.build()
}
}
```
--------------------------------
### Spring Boot Compatibility Matrix
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/appendix.adoc
This section provides a compatibility matrix for Spring Modulith versions against Spring Boot and jMolecules versions.
```APIDOC
## Spring Boot Compatibility
This section provides a compatibility matrix for Spring Modulith versions against Spring Boot and jMolecules versions.
|===
|Spring Modulith Version
|Spring Boot Version +
(compiled against)
|Spring Boot Version +
(examples tested against)
|jMolecules +
(compiled)
|jMolecules +
(tested)
|2.0 (snapshot)
|4.0 SNAPSHOT
|4.0 SNAPSHOT and milestones
|2023.2
|2023.2, 2025.0 RC2
|1.4
|3.5
|3.1, 3.2, 3.3, 3.4, 3.5
|2023.2
|2023.2, 2025.0 RC2
|1.3
|3.4
|3.1, 3.2, 3.3, 3.4, 3.5
|2023.1
|2023.1, 2023.2, 2025.0 RC2
|1.2
|3.3
|3.1, 3.2, 3.3, 3.4
|2023.1
|2023.1, 2023.2, 2025.0 RC2
|1.1
|3.2
|3.1, 3.2, 3.3, 3.4
|2023.1
|2023.1, 2023.2, 2025.0 RC2
|===
```
--------------------------------
### Namastack Outbox Event Externalization Output
Source: https://github.com/spring-projects/spring-modulith/blob/main/spring-modulith-examples/spring-modulith-example-outbox/readme.adoc
Shows the log output when using Namastack for outbox event externalization. It highlights application bootstrap configuration, outbox registration, event publication, persistence to the outbox table, and asynchronous processing to Kafka.
```log
14:53:40.959 D - main : Configuring event externalization to export events annotated with @Externalized in packages: [example, ...] <1>
…
14:53:42.225 D - main : Registering domain event outbox externalization to Kafka… <2>
14:53:42.227 D - main : Registering domain event externalization via outbox… <3>
…
14:53:42.247 I - main : Triggering order completion… <4>
14:53:42.251 D - main : Scheduling event of type example.order.OrderCompleted to outbox for target order.OrderCompleted. <5>
…
14:53:44.494 D - eduler-1 : Found 1 record keys to process <6>
…
14:53:44.767 D - eduler-1 : Finished processing 1 record keys <7>
```
--------------------------------
### Defining a Stimulus: Bean Invocation
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Demonstrates initiating a `Scenario` by invoking a Spring bean's method. This is also executed within a transaction callback.
```java
// Start with a bean invocation
scenario.stimulate(() -> someBean.someMethod(…)).…
```
```kotlin
// Start with a bean invocation
scenario.stimulate(Runnable { someBean.someMethod(…) }).…
```
--------------------------------
### Declare Application Module as Open (Java)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Use the @ApplicationModule annotation with Type.OPEN on package-info.java to make an application module open. This allows broader access to internal types from other modules.
```java
@org.springframework.modulith.ApplicationModule(
type = Type.OPEN
)
package example.inventory;
```
--------------------------------
### Application Module Integration Test Bootstrap Log Output
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Observe detailed log output when running `@ApplicationModuleTest` to understand how the Spring Boot bootstrap is customized for the specific application module.
```text
. ____ _ __ _ _
/\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\/ ___)| |_)| | | | | |\__, | ) ) ) )
' |____| .__|_| |_|_| |\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.0.0-SNAPSHOT)
… - Bootstrapping @ApplicationModuleTest for example.order in mode STANDALONE (class example.Application)…
… - ======================================================================================================
… - ## example.order ##
… - > Logical name: order
… - > Base package: example.order
… - > Direct module dependencies: none
… - > Spring beans:
… - + ….OrderManagement
… - + ….internal.OrderInternal
… - Starting OrderIntegrationTests using Java 17.0.3 …
… - No active profile set, falling back to 1 default profile: "default"
… - pass:quotes[**Re-configuring auto-configuration and entity scan packages to: example.order.**]
```
--------------------------------
### Publishing Application Event via ApplicationEventPublisher
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/events.adoc
Demonstrates publishing an application event using Spring's ApplicationEventPublisher to decouple modules.
```java
@Service
@RequiredArgsConstructor
public class OrderManagement {
private final ApplicationEventPublisher events;
private final OrderInternal dependency;
@Transactional
public void complete(Order order) {
// State transition on the order aggregate go here
events.publishEvent(new OrderCompleted(order.getId()));
}
}
```
```kotlin
@Service
class OrderManagement(val events: ApplicationEventPublisher, val dependency: OrderInternal) {
@Transactional
fun complete(order: Order) {
events.publishEvent(OrderCompleted(order.id))
}
}
```
--------------------------------
### Declare Spring Modulith JobRunr Starter (Gradle)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/events.adoc
Add the Spring Modulith JobRunr starter dependency to your Gradle project to enable JobRunr support for event externalization.
```gradle
dependencies {
implementation 'org.springframework.modulith:spring-modulith-starter-jobrunr'
}
```
--------------------------------
### Using the Scenario API in a JUnit 5 Test
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Shows how to declare the `Scenario` API as a test method parameter in tests annotated with `@ApplicationModuleTest`.
```java
@ApplicationModuleTest
class SomeApplicationModuleTest {
@Test
public void someModuleIntegrationTest(Scenario scenario) {
// Use the Scenario API to define your integration test
}
}
```
```kotlin
@ApplicationModuleTest
class SomeApplicationModuleTest {
@Test
fun someModuleIntegrationTest(scenario: Scenario) {
// Use the Scenario API to define your integration test
}
}
```
--------------------------------
### Simulated Kafka Operations for Testing
Source: https://github.com/spring-projects/spring-modulith/blob/main/spring-modulith-examples/spring-modulith-example-kafka/readme.adoc
This bean simulates Kafka operations by logging messages, allowing tests to run without a live Kafka instance. It's declared in the test application context.
```java
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import org.springframework.kafka.support.ProducerListener;
import java.util.HashMap;
@Configuration
class KafkaConfiguration {
@Bean
public ProducerListener producerListener() {
return new ProducerListener() {
@Override
public void onError(String topic, Integer partition, String key, String value, Throwable exception) {
super.onError(topic, partition, key, value, exception);
System.err.println("Error sending message to topic \"%s\": %s".formatted(topic, exception.getMessage()));
}
@Override
public void onSend(String topic, Integer partition, String key, String value) {
super.onSend(topic, partition, key, value);
System.out.println("Sending message \"%s\" to topic \"%s\"".formatted(value, topic));
}
};
}
@Bean
public KafkaTemplate kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
@Bean
public ProducerFactory producerFactory() {
return new DefaultKafkaProducerFactory<>(producerProps());
}
private HashMap producerProps() {
var props = new HashMap();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
return props;
}
}
```
--------------------------------
### Observability Spans - Tag Keys
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
Details on the tag keys used for module entry spans.
```APIDOC
## Observability Spans
### Module Entry Span
#### Tag Keys
|===
|Name | Description
|`module.identifier`|The identifier of the module.
|`module.invocation-type`|Type of invocation ("event listener" or "bean").
|`module.method`|Method executed on a module.
|`module.name`|Name of the module.
|===
```
--------------------------------
### Define a Named Interface in package-info
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Expose a package as a named interface to allow other modules to access its contents.
```java
@org.springframework.modulith.NamedInterface("spi")
package example.order.spi;
```
```kotlin
package example.order.spi
import org.springframework.modulith.PackageInfo
import org.springframework.modulith.NamedInterface
@PackageInfo
@NamedInterface("spi")
class ModuleMetadata {}
```
--------------------------------
### Declare Allowed Dependencies to All Named Interfaces
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Use the asterisk wildcard to permit dependencies on all named interfaces of a target module.
```java
@org.springframework.modulith.ApplicationModule(
allowedDependencies = "order :: *"
)
package example.inventory;
```
```kotlin
package example.inventory
import org.springframework.modulith.ApplicationModule
import org.springframework.modulith.PackageInfo
@ApplicationModule(
allowedDependencies = "order :: *"
)
@PackageInfo
class ModuleMetadata {}
```
--------------------------------
### Declare Spring Modulith JobRunr Starter (Maven)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/events.adoc
Add the Spring Modulith JobRunr starter dependency to your Maven project to enable JobRunr support for event externalization.
```xml
org.springframework.modulith
spring-modulith-starter-jobrunr
```
--------------------------------
### Providing a Custom ModulithObservationConvention
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/production-ready.adoc
Configure a custom observation convention by providing a ModulithObservationConvention bean. This allows for fine-grained control over how observations are created.
```java
@Configuration
class ObservabilityConfiguration {
@Bean
ModulithObservationConvention observationConvention() {
return new CustomModulithObservationConvention();
}
}
```
--------------------------------
### Customize Scenario Execution in Java
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Customizes the execution of an individual scenario by setting a maximum duration for event arrival. This allows fine-tuning of test timeouts.
```java
scenario.publish(new MyApplicationEvent(…))
.customize(conditionFactory -> conditionFactory.atMost(Duration.ofSeconds(2)))
.andWaitForEventOfType(SomeOtherEvent.class)
.matching(event -> …)
.toArriveAndVerify(event -> …);
```
--------------------------------
### Configure Application Modules with @Modulithic
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Enable Spring Modulith features on the main application class.
```java
package example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.modulith.Modulithic;
@Modulithic
@SpringBootApplication
class MyApplication {
public static void main(String... args) {
SpringApplication.run(MyApplication.class, args);
}
}
```
```kotlin
package example
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.modulith.Modulithic
@Modulithic
@SpringBootApplication
class MyApplication
fun main(args: Array) {
runApplication(*args)
}
```
--------------------------------
### Implement Custom ApplicationModuleDetectionStrategy
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Use this strategy to define custom discovery logic for module base packages and named interfaces. The builder API allows recursive matching of specific package names like 'api'.
```java
package example;
class CustomApplicationModuleDetectionStrategy implements ApplicationModuleDetectionStrategy {
@Override
public Stream getModuleBasePackages(JavaPackage basePackage) {
// Your module detection goes here
}
@Override
NamedInterfaces detectNamedInterfaces(JavaPackage basePackage, ApplicationModuleInformation information) {
return NamedInterfaces.builder()
.recursive()
.matching("api")
.build();
}
}
```
```kotlin
package example
class CustomApplicationModuleDetectionStrategy : ApplicationModuleDetectionStrategy {
override fun getModuleBasePackages(basePackage: JavaPackage): Stream {
// Your module detection goes here
}
override fun detectNamedInterfaces(basePackage: JavaPackage, information: ApplicationModuleInformation): NamedInterfaces {
return NamedInterfaces.builder()
.recursive()
.matching("api")
.build()
}
}
```
--------------------------------
### Customize Scenario Execution in Kotlin
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Customizes an individual scenario in Kotlin by applying a maximum duration for event arrival. This provides granular control over test timing.
```kotlin
scenario.publish(MyApplicationEvent(…))
.customize { it.atMost(Duration.ofSeconds(2)) }
.andWaitForEventOfType(SomeOtherEvent::class.java)
.matching { event -> … }
.toArriveAndVerify { event -> … }
```
--------------------------------
### Create an Application Module Integration Test
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Annotate a JUnit test class with `@ApplicationModuleTest` within an application module's package to initiate module-specific integration testing.
```java
package example.order;
@ApplicationModuleTest
class OrderIntegrationTests {
// Individual test cases go here
}
```
```kotlin
package example.order
@ApplicationModuleTest
class OrderIntegrationTests {
// Individual test cases go here
}
```
--------------------------------
### Spring Modulith Configuration Properties
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/appendix.adoc
This section details the various configuration properties available for Spring Modulith, including their default values and descriptions.
```APIDOC
## Spring Modulith Configuration Properties
This section details the various configuration properties available for Spring Modulith, including their default values and descriptions.
|===
|Property|Default value|Description
|`spring.modulith.default-async-termination`
|`true`
|Whether to configure defaults for the async processing termination, namely to wait for task completion for 2 seconds. See `TaskExecutionProperties` for details.
|`spring.modulith.detection-strategy`
|none
|The strategy to be applied to detect application modules. Can either be the class name of a custom implementation of `ApplicationModuleDetectionStrategy` or `direct-subpackages` (which is also the final fallback if nothing is configured) or `explicitly-annotated` to only select packages explicitly annotated with `@ApplicationModule` or jMolecules' `@Module`. See xref:fundamentals.adoc#customizing-modules[Customize Application Module Detection] for details.
|`spring.modulith.events.completion-mode`
|`update`
a|How to mark an event publication as completed. The following values are supported:
* `update` (default) -- Sets the completion date on the event publication entry.
* `delete` -- Removes the event publication entry.
Completed event publications are not available via `CompletedEventPublications`.
* `archive` -- Removes the event publication entry from the primary database abstraction (table, collection or node) and creates one in a archive (a table, collection or node of same schema).
For details, see xref:events.adoc#publication-registry.completion[Event Publication Completion].
|`spring.modulith.events.externalization.enabled`
|`true`
|Whether to enable event externalization.
|`spring.modulith.events.externalization.mode`
|`module-listener`
|The mode of event externalization. See xref:events.adoc#externalization[Event externalizazion] for details. The following values are supported:
* `module-listener` (default) -- Events are externalized through an `@ApplicationModuleListener`.
* `outbox` -- Events are externalized through an actual outbox implementation.
|`spring.modulith.events.externalization.serialize-externalization`
|`false`
|Whether to serialize event externalization to brokers.
|`spring.modulith.events.jdbc.schema-initialization.enabled`
|`true`
|Whether to initialize the JDBC event publication schema.
|`spring.modulith.events.jdbc.schema`
|
|The schema name for the event publication table. If not specified, the table will not be schema-qualified.
|`spring.modulith.events.jdbc.use-legacy-structure`
|`false`
|Whether to use the legacy event publication database structure.
|`spring.modulith.events.kafka.enable-json`
|`true`
|Whether to enable JSON support for `KafkaTemplate`.
|`spring.modulith.events.mongodb.transaction-management.enabled`
|`true`
|Whether to automatically enable transactions for MongoDB. Requires the database to be run with a replica set.
|`spring.modulith.events.neo4j.event-index.enabled`
|`false`
|Whether to create indexes on the Neo4j event publication event hash property.
|`spring.modulith.events.rabbitmq.enable-json`
|`true`
|Whether to enable JSON support for `RabbitTemplate`.
|`spring.modulith.events.registry-trigger-annotation`
|
|The fully-qualified class name of an annotation that is supposed to trigger an entry in the Event Publication Registry. By default, all methods (meta-)annotated with `@TransactionalEventListener` are considered. Set this to `@ApplicationModuleListener` if you only want to create entries in the Event Publication registry for methods annotated with that.
|`spring.modulith.events.republish-outstanding-events-on-restart`
|`false`
|Whether to republish outstanding event publications on restarts of the application. Usually not recommended in multi-instance deployments as other instances might still be processing events.
|`spring.modulith.events.staleness.check-interval`
|`Duration.ofMinutes(1)`
|The interval at which the xref:events.adoc#publication-registry.lifecycle.staleness[Staleness Monitor] runs to mark stale event publications as failed.
|`spring.modulith.events.staleness.processing`
|`Duration.ZERO`
|After which duration an event publication in the processing state is considered stale.
|===
```
--------------------------------
### Moments Configuration Properties
Source: https://github.com/spring-projects/spring-modulith/blob/main/spring-modulith-moments/readme.adoc
Configuration properties available under the moduliths.moments namespace to customize the behavior of the Moments module.
```APIDOC
## Configuration Properties: moduliths.moments
### Description
These properties allow customization of the Moments module behavior, including enabling/disabling the module, time machine functionality, and time zone settings.
### Properties
- **enabled** (boolean) - Default: true - Whether to enable Moments in the application.
- **enable-time-machine** (boolean) - Default: false - Set to true to expose TimeMachine bean to shift time.
- **granularity** (string) - Default: hours - Granularity to publish events (e.g., hours, days).
- **locale** (string) - Default: Locale.default() - Locale used to determine the start date of the week.
- **quarter-start-month** (string) - Default: January - The month in which the first quarter starts.
- **zone-id** (string) - Default: UTC - The time zone used to determine dates and times for events.
```
--------------------------------
### Verify Application Modularity with JUnit
Source: https://github.com/spring-projects/spring-modulith/blob/main/etc/introducing-spring-modulith.adoc
Use this test to verify the application's modular structure. It checks if code adheres to the defined module conventions and will fail the build if dependencies violate these rules.
```java
class ModularityTests {
@Test
void verifyModularity() {
ApplicationModules.of(Application.class).verify();
}
}
```
--------------------------------
### Wait for State Change in Java
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/testing.adoc
Publishes an event and waits for a state change by invoking a method on a bean. Use this when the completion signal is a change in application state rather than an event.
```java
scenario.publish(new MyApplicationEvent(…))
.andWaitForStateChange(() -> someBean.someMethod(…)))
.andVerify(result -> …);
```
--------------------------------
### Define a dynamic routing key via SpEL expression
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/events.adoc
Use the @Externalized annotation with a $target::$key pattern to define dynamic routing keys using SpEL expressions.
```java
@Externalized("customer-created::#{#this.getLastname()}") // <2>
class CustomerCreated {
String getLastname() { // <1>
// …
}
}
```
```kotlin
@Externalized("customer-created::#{#this.getLastname()}") // <2>
class CustomerCreated {
fun getLastname(): String { // <1>
// …
}
}
```
--------------------------------
### Add Spring Modulith Runtime Dependency (Gradle)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/runtime.adoc
Include the `spring-modulith-runtime` JAR in your project's Gradle dependencies to enable runtime support.
```xml
dependencies {
runtimeOnly 'org.springframework.modulith:spring-modulith-runtime'
}
```
--------------------------------
### Configure Explicit Module Dependencies (Java)
Source: https://github.com/spring-projects/spring-modulith/blob/main/src/docs/antora/modules/ROOT/pages/fundamentals.adoc
Specify allowed dependencies for a module using the @ApplicationModule annotation with the 'allowedDependencies' attribute on package-info.java. This restricts module interactions.
```java
@org.springframework.modulith.ApplicationModule(
allowedDependencies = "order"
)
package example.inventory;
```