Introducing Spring Modulith

Modularity has long been a sought-after goal in software engineering, offering benefits like improved maintainability, scalability, and testability.

 

In this introduction, we will explore the core concepts, features, and advantages of Spring Modulith, empowering you to embrace this cutting-edge approach to build high-quality applications that support changing business requirements.

Application modules

Each direct sub-package of the main package is considered an application module package by default (you can change strategies for how modules are registered). This package is part of the public API and can be accessed by any module. All sub-packages are considered internal, and Spring Beans are only accessible inside the module itself.

Verifying application module structure

Verification can be done simply by writing a unit test to verify the following:

If jmolecules-archunit is present on the classpath, then ArchUnit Domain-Driven-Design rules will be verified. You can check them here.

Working with application events

You can use asynchronous, transactional event handling for inter-module communication to achieve loose coupling between application modules.

 

On event publication, Spring Modulith’s event registry publication persists all interested listeners into the repository and writes completed logs afterward.

 

This way, if it fails, it can be retried again. By default, all incomplete event publications are resubmitted at application startup (you can change this behavior based on your needs).

 

JDBC, JPA, and Mongodb event repositories (and spring boot starters) are available.

 

To create a listener for a particular event, annotate your Spring Bean method with @ApplicationModuleListener annotation.

 

Publishing events can be done via Spring’s ApplicationEventPublisher or Spring Data AggregateRoot abstraction.

 

In the next release (1.1.0), there is going to be support for External events via @Externalized annotation to push events to external systems. JMS, Kafka, and AMQP protocols will be supported for now.

Integration testing application modules

To ease integration testing of asynchronous, transactional event handling Spring Modulith brings Scenario abstraction, which has helpful methods to publish and receive-verify events.

 

There are also three modes to the bootstrapping testing module:

Moments: A passage of time events API

Business processes involve the execution of specific tasks, actions, or workloads scheduled for a later date (Customer birthday, Invoice payment become overdue, etc.). Consider the flow of time as simply another instance of a Domain Event when a business-relevant occurrence takes place.

  

Spring Modulith defines the following events:

Application code can listen and react to these events, and this way, “scheduling” is part of our Domain Language.

 

Another great benefit is TimeMachine, which can be used to shift time in the future and trigger all-time events. This is very useful for integration testing, for example:

Documenting application modules

It’s very easy to generate documentation from Application modules like Spring beans, aggregate roots, published events and event listeners as well as configuration properties:

We can also visualize dependencies with generated canvases:

Module initializers

Use module initializers to run some module code before the application starts. It will start modules in order of dependent module structure.

Spring Modulith Actuator and tracing

Spring Modulith provides us a new actuator endpoint, “actuator/modulith”, which provides us Module information and can create Micrometer spans to visualize spans in tracking visualization tools.

Conclusion

Spring Modulith gives us power and ease to write well-designed application modules with Domain Driven Design principles and offers benefits like improved maintainability, scalability, and testability.

In this article:
Published:
22 November 2023

Related posts