Spring Modulith : du monolith aux modules

Publié le 16/03/2026 Source : sfeir.dev

Dans le développement Java, de nombreuses applications commencent comme des monolithes simples, mais deviennent rapidement difficiles à maintenir à mesure qu’elles grandissent.
La modularisation est alors une étape clé pour améliorer la lisibilité, la testabilité et la maintenabilité.

Spring Modulith est une solution qui permet de découper un monolithe en modules logiques tout en restant dans le cadre d’un projet Spring Boot classique.

Présentation de Spring Modulith

Spring Modulith est un framework léger qui s’intègre à Spring Boot pour aider les développeurs à structurer leur monolithe en modules. Chaque module peut publier ou écouter des événements, exposer ou cacher certains packages, et disposer d’une documentation automatique. Modulith propose également un Documenter pour générer des diagrammes UML et des Canvas de modules, facilitant la visualisation de l’architecture.

Les concepts principaux :

⚖️ Avantages et inconvénients

➕ Avantages

➖ Inconvénients

Contrôle des imports et liens avec ArchUnit

Spring Modulith s’appuie sur ArchUnit pour analyser les dépendances entre modules. Même si Java autorise les imports directs, Modulith détectera grâce à ArchUnit toute utilisation interdite (par exemple l’accès à une classe située dans un package internal).
Cela permet d’automatiser la vérification de la modularité et de garantir le respect des règles d’architecture au fil des évolutions du code.

Maîtrisez votre architecture Spring Boot avec ArchUnit

Mise en place

Pour commencer avec Spring Modulith dans un projet Spring Boot, il suffit d’ajouter les dépendances Maven suivantes :

<dependencies>
    <dependency>
        <groupId>org.springframework.modulith</groupId>
        <artifactId>spring-modulith-starter-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.modulith</groupId>
        <artifactId>spring-modulith-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.modulith</groupId>
            <artifactId>spring-modulith-bom</artifactId>
            <version>${spring-modulith.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Ensuite, la détection des modules et des événements se fait automatiquement via la configuration Spring classique.

Exemple pratique

prenons le projet Spring Boot suivant :

Nous avons ici 2 modules distincts :

Module Product

Le module Product gère les produits et publie un événement lors de la création :

@Service
public class ProductService {
    private final ApplicationEventPublisher events;

    public ProductService(ApplicationEventPublisher events) {
        this.events = events;
    }

    public void create(Product product) {
        events.publishEvent(
            new NotificationDTO(new Date(), "SMS", product.getName())
        );
    }
}

org.springframework.modulith.core.Violations: - Module 'product' depends on non-exposed type fr.eletutour.modulith.notification.internal.model.NotificationType within module 'notification'!
Method <fr.eletutour.modulith.product.ProductService.create(fr.eletutour.modulith.product.Product)> gets field <fr.eletutour.modulith.notification.internal.model.NotificationType.SMS> in (ProductService.java:36)
- Module 'product' depends on non-exposed type fr.eletutour.modulith.notification.internal.model.Notification within module 'notification'!
Method <fr.eletutour.modulith.product.ProductService.create(fr.eletutour.modulith.product.Product)> calls constructor <fr.eletutour.modulith.notification.internal.model.Notification.<init>(java.util.Date, fr.eletutour.modulith.notification.internal.model.NotificationType, java.lang.String)> in (ProductService.java:36)

exemple de logs de violations lors des tests.


Module Notification

Le module Notification écoute les événements publiés par Product et transforme les DTO en entités internes pour traitement :

@Service
public class NotificationService {
    @EventListener
    public void notificationEvent(NotificationDTO event) {
        Notification notification = toEntity(event);
        LOG.info("Received notification for product {} on {} via {}",
            notification.getProductname(),
            notification.getDate(),
            notification.getType()
        );
    }

    private Notification toEntity(NotificationDTO event) {
        return new Notification(
            event.getDate(),
            NotificationType.valueOf(event.getFormat()),
            event.getProductName()
        );
    }
}

Tests Modulith

Le framework fournit également des outils pour tester et documenter les modules :

@Test
void createApplicationModuleModel() {
    ApplicationModules modules = ApplicationModules.of(Application.class);
    modules.forEach(System.out::println);
}

@Test
void verifiesModularStructure() {
    ApplicationModules modules = ApplicationModules.of(Application.class);
    modules.verify();
}

@Test
void createModuleDocumentation() {
    ApplicationModules modules = ApplicationModules.of(Application.class);
    new Documenter(modules)
        .writeDocumentation()
        .writeIndividualModulesAsPlantUml();
}

La documentation générée se trouvera ensuite dans le repertoire target/spring-modulith-docs

Exemple de documentation générée

Liaison avec la méthodologie DDD

Spring Modulith s’intègre naturellement avec Domain-Driven Design (DDD) :

Conclusion

Spring Modulith offre une approche pragmatique pour transformer un monolithe en modules cohérents et bien documentés, tout en restant dans un projet Spring Boot classique.
Grâce aux événements et aux Canvas, il est possible de visualiser les flux, d’assurer l’indépendance des modules et de faciliter la maintenance sur le long terme.

C’est une solution idéale pour des applications monolithiques qui souhaitent gagner en clarté, testabilité et évolutivité, tout en respectant les principes de DDD.