Production-ready Features

Spring Modulith provides support to expose architectural information about your system as a Spring Boot actuator endpoint as well as observing the interaction between application modules by capturing metrics and traces. As a production-ready application is likely to require both, the most convenient way to activate those features is to use the Spring Modulith Insight starter as follows:

Using the Spring Modulith Insight starter
  • Maven

  • Gradle

<dependency>
  <groupId>org.springframework.modulith</groupId>
  <artifactId>spring-modulith-starter-insight</artifactId>
  <version>1.2.5</version>
  <scope>runtime</scope>
</dependency>
dependencies {
  runtimeOnly 'org.springframework.modulith:spring-modulith-starter-insight:1.2.5'
}

This will include the actuator and observability support as well as Spring Boot’s actuator startup for general support for actuators. Note, that you will still have to add further dependencies to connect your application to your monitoring tools such as Zipkin, Wavefront etc. usually via OpenTelemetry or Brave. Find more information on that in the corresponding section of Spring Boot’s reference documentation.

Application Module Actuator

The application module structure can be exposed as Spring Boot actuator. To enable the actuator, add the spring-modulith-actuator dependency to the project:

Using the Spring Modulith actuator support
  • Maven

  • Gradle

<dependency>
  <groupId>org.springframework.modulith</groupId>
  <artifactId>spring-modulith-actuator</artifactId>
  <version>1.2.5</version>
  <scope>runtime</scope>
</dependency>

<!-- Spring Boot actuator starter required to enable actuators in general -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
  <version>…</version>
  <scope>runtime</scope>
</dependency>
dependencies {
  runtimeOnly 'org.springframework.modulith:spring-modulith-actuator:1.2.5'
}

<!-- Spring Boot actuator starter required to enable actuators in general -->
dependencies {
  runtimeOnly 'org.springframework.boot:spring-boot-starter-actuator'
}

Running the application will now expose an modulith actuator resource:

Accessing the actuator HTTP resource
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
    }
  }
}
1 The modulith actuator resource advertised.

The modulith resource adheres to the following structure:

Table 1. The JSON structure of the application modules actuator
JSONPath Description

$.{moduleName}

The technical name of an application module. Target for module references in dependencies.target.

$.{moduleName}.displayName

The human-readable name of the application module.

$.{moduleName}.basePackage

The application module’s base package.

$.{moduleName}.dependencies[]

All outgoing dependencies of the application module

$.{moduleName}.dependencies[].target

The name of the application module depended on. A reference to a {moduleName}.

$.{moduleName}.dependencies[].types[]

The types of dependencies towards the target module. Can either be DEFAULT (simple type dependency), USES_COMPONENT (Spring bean dependency) or EVENT_LISTENER.

An example module arrangement would look like this:

An example response for the application modules actuator
{
  "a": {
    "basePackage": "example.a",
    "displayName": "A",
    "dependencies": []
  },
  "b": {
    "basePackage": "example.b",
    "displayName": "B",
    "dependencies": [ {
      "target": "a",
      "types": [ "EVENT_LISTENER", "USES_COMPONENT" ]
    } ]
  }
}

Observing Application Modules

The interaction between application modules can be intercepted to create Micrometer spans to ultimately end up in traces you can visualize in tools like Zipkin. To activate the instrumentation add the following runtime dependency to your project:

Using the Spring Modulith observability support
  • Maven

  • Gradle

<dependency>
  <groupId>org.springframework.modulith</groupId>
  <artifactId>spring-modulith-observability</artifactId>
  <version>1.2.5</version>
  <scope>runtime</scope>
</dependency>
dependencies {
  runtimeOnly 'org.springframework.modulith:spring-modulith-observability:1.2.5'
}
You will have to configure additional infrastructure dependencies depending on the tooling you want to pipe the observability metadata in. For details, please check the corresponding Spring Boot documentation on which dependencies to include for your setup.

This will cause all Spring components that are part of the application module’s API being decorated with an aspect that will intercept invocations and create Micrometer spans for them. A sample invocation trace can be seen below:

observability
Figure 1. A sample module invocation trace

In this particular case, triggering the payment changes the state of the order which then causes an order completion event being triggered. This gets picked up asynchronously by the engine that triggers another state change on the order, works for a couple of seconds and triggers the final state change on the order in turn.