
Création de ses propres starters Spring Boot
Apprenez à créer vos propres starters Spring Boot pour encapsuler l'auto-configuration et simplifier l'intégration de bibliothèques personnalisées ou de configurations communes.
Introduction : Pourquoi créer son propre Starter ?
L'un des atouts majeurs de Spring Boot est son écosystème de "starters" (`spring-boot-starter-*`). Ces starters sont des descripteurs de dépendances pratiques qui simplifient l'intégration de diverses technologies (web, data, sécurité, etc.) en ajoutant les bonnes dépendances et en fournissant une auto-configuration sensée.
Mais que faire si vous développez une bibliothèque interne réutilisable, une infrastructure commune à plusieurs projets, ou si vous souhaitez standardiser la configuration d'une bibliothèque tierce au sein de votre organisation ? C'est là qu'intervient la création de vos propres starters Spring Boot personnalisés.
Créer un starter personnalisé permet d'encapsuler non seulement les dépendances nécessaires mais aussi l'auto-configuration associée, offrant ainsi aux utilisateurs de votre starter une expérience "à la Spring Boot" : ajouter une dépendance, éventuellement quelques propriétés de configuration, et la fonctionnalité est prête à l'emploi. Cela favorise la réutilisation, réduit le code boilerplate dans les applications consommatrices et assure la cohérence des configurations.
Anatomie d'un Starter personnalisé : Deux modules clés
Un starter Spring Boot bien conçu est généralement composé de deux modules Maven ou Gradle distincts :
- Le module d'auto-configuration (`*-spring-boot-autoconfigure`) :
- Contient la logique d'auto-configuration principale. C'est ici que vous définissez les classes `@Configuration`, les beans conditionnels (`@ConditionalOn...`), les classes `@ConfigurationProperties`, etc.
- Ce module déclare les dépendances optionnelles vers les bibliothèques nécessaires pour que l'auto-configuration fonctionne (par exemple, si votre configuration dépend de Spring MVC, vous la déclarez ici comme optionnelle).
- Important : Les applications utilisatrices ne devraient JAMAIS inclure directement ce module comme dépendance.
- Le module Starter (`*-spring-boot-starter`) :
- C'est le module que les utilisateurs finaux ajoutent comme dépendance à leur projet.
- Il est souvent "vide" en termes de code Java. Son rôle principal est d'agir comme un agrégateur de dépendances.
- Il déclare une dépendance obligatoire vers le module d'auto-configuration (`*-spring-boot-autoconfigure`).
- Il déclare les dépendances obligatoires vers la bibliothèque principale que le starter configure (par exemple, `my-awesome-library`) et toute autre dépendance essentielle.
Cette séparation garantit que l'auto-configuration est bien découplée et que le starter fournit une vue claire des dépendances requises pour l'utilisateur.
Le module d'auto-configuration en détail
C'est le coeur de votre starter. Il contient une ou plusieurs classes annotées avec `@Configuration` (ou plus spécifiquement `@AutoConfiguration` depuis Spring Boot 2.7 pour une meilleure sémantique et ordonnancement).
Les éléments clés de ce module sont :
- Classes `@AutoConfiguration` / `@Configuration` : Définissent les beans que votre starter va potentiellement créer.
- Annotations `@ConditionalOn...` : Le point crucial pour l'auto-configuration. Elles permettent de ne créer les beans que si certaines conditions sont remplies :
- `@ConditionalOnClass` : Le bean n'est créé que si une classe spécifique est présente dans le classpath (par exemple, ne configurer un bean lié à JPA que si les classes JPA sont là).
- `@ConditionalOnMissingBean` : Le bean n'est créé que si aucun autre bean du même type n'a déjà été défini par l'utilisateur ou une autre configuration (permet à l'utilisateur de surcharger votre configuration par défaut).
- `@ConditionalOnProperty` : Le bean n'est créé que si une propriété spécifique est définie (ou a une valeur particulière) dans l'environnement Spring (par exemple, `myapp.feature.enabled=true`).
- `@ConditionalOnBean` : Le bean n'est créé que si un autre bean spécifique existe déjà.
- Et bien d'autres (`@ConditionalOnWebApplication`, `@ConditionalOnResource`, etc.).
- Classes `@ConfigurationProperties` : Définissent des objets typés pour regrouper les propriétés de configuration personnalisées de votre starter (par exemple, `myapp.service.url`, `myapp.service.timeout`). Elles sont préfixées avec `@ConfigurationProperties("myapp.service")`.
- Annotation `@EnableConfigurationProperties` : Utilisée sur votre classe `@Configuration` pour enregistrer votre/vos classe(s) `@ConfigurationProperties` et les rendre disponibles pour l'injection et la liaison de propriétés.
Exemple simple (`my-service-spring-boot-autoconfigure`) :
// Classe de propriétés
@ConfigurationProperties("myservice")
public class MyServiceProperties {
/** Enable MyService integration. */
private boolean enabled = true;
/** URL of the external service. */
private String url = "http://default.example.com";
// Getters & Setters...
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
}
// Classe d'auto-configuration
@AutoConfiguration // Ou @Configuration
@ConditionalOnClass(MyServiceClient.class) // Ne configurer que si MyServiceClient est au classpath
@ConditionalOnProperty(prefix = "myservice", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(MyServiceProperties.class)
public class MyServiceAutoConfiguration {
@Bean
@ConditionalOnMissingBean // Ne crée le bean que si l'utilisateur n'en a pas défini un
public MyServiceClient myServiceClient(MyServiceProperties properties) {
System.out.println("Auto-configuring MyServiceClient with URL: " + properties.getUrl());
// Logique pour créer et configurer le client avec l'URL des propriétés
return new MyServiceClient(properties.getUrl());
}
// Définir d'autres beans conditionnels ici...
}
// Classe hypothétique de la bibliothèque
class MyServiceClient {
public MyServiceClient(String url) { /* ... */ }
// ... méthodes du client
}
Le module Starter en détail
Ce module est beaucoup plus simple. Il ne contient généralement pas de code source Java. Sa seule responsabilité est de déclarer les bonnes dépendances via son fichier `pom.xml` (Maven) ou `build.gradle` (Gradle).
Exemple (`my-service-spring-boot-starter/pom.xml`) :
4.0.0
com.example
my-service-spring-boot-starter
1.0.0
com.example
my-service-spring-boot-autoconfigure
${project.version}
-->
Respectez la convention de nommage `*-spring-boot-starter` pour que votre starter soit facilement identifiable.
Mécanisme de découverte de l'auto-configuration
Comment Spring Boot découvre-t-il la classe `MyServiceAutoConfiguration` définie dans le module `autoconfigure` lorsque l'utilisateur ajoute uniquement le module `starter` ?
Historiquement (avant Spring Boot 2.7), cela se faisait via un fichier `META-INF/spring.factories` dans le JAR du module `autoconfigure`. Ce fichier listait les classes d'auto-configuration :
# META-INF/spring.factories (Legacy)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfigure.MyServiceAutoConfigurationDepuis Spring Boot 2.7 et surtout avec Spring Boot 3.0+, la méthode préférée et recommandée est d'utiliser un fichier d'importations dédié dans le module `autoconfigure`. Créez le fichier :
`src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`
Et listez simplement le nom complet de votre classe d'auto-configuration, une par ligne :
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (Moderne)
com.example.autoconfigure.MyServiceAutoConfiguration
# com.example.autoconfigure.AnotherAutoConfigurationSpring Boot scanne ces fichiers `.imports` dans tous les JARs du classpath pour trouver et charger les auto-configurations candidates.
Bonnes pratiques et tests
Utilisez les conditions judicieusement : N'abusez pas des conditions, mais utilisez-les pour rendre votre starter non intrusif et permettre aux utilisateurs de surcharger facilement les beans par défaut (`@ConditionalOnMissingBean` est votre ami).
Namespacez vos propriétés : Utilisez un préfixe clair et unique pour vos `@ConfigurationProperties` (ex: `myapp.myservice.*`).
Documentez : Fournissez une documentation claire sur les propriétés de configuration disponibles et sur la manière d'utiliser votre starter.
Métadonnées de configuration : Ajoutez la dépendance `spring-boot-configuration-processor` à votre module `autoconfigure` pour générer automatiquement les métadonnées (`META-INF/spring-configuration-metadata.json`). Cela active l'auto-complétion et la documentation des propriétés dans les IDEs.
Testez rigoureusement : Les starters nécessitent des tests d'intégration pour vérifier que l'auto-configuration fonctionne correctement dans différents scénarios :
- Configuration par défaut.
- Propriété d'activation désactivée.
- Utilisateur fournissant son propre bean (test de `@ConditionalOnMissingBean`).
- Classe requise manquante (test de `@ConditionalOnClass`).
- Différentes valeurs de propriétés.
Conclusion
Créer ses propres starters Spring Boot est une technique puissante pour encapsuler la configuration et les dépendances de bibliothèques ou de fonctionnalités communes. En suivant la structure à deux modules (autoconfigure et starter), en utilisant judicieusement les annotations conditionnelles et `@ConfigurationProperties`, et en déclarant correctement l'auto-configuration via le fichier `.imports`, vous pouvez offrir une expérience d'intégration simplifiée et cohérente aux utilisateurs de vos composants.
C'est un excellent moyen de promouvoir les bonnes pratiques, de réduire la duplication de code et de contribuer à l'écosystème Spring Boot au sein de votre organisation ou même de la communauté open-source.