Spring a une solution simple pour découpler ton code sans ajouter de dépendances.
Quelques annotations magiques... au final c'’est juste une implémentation propre du bon vieux pattern Observer qui semble sous utilisé dans la communauté Spring.
Le problème classique
Imaginons :
Quand une commande est passée, il faut envoyer un email, logger l’action, invalider un cache, et notifier un service d’analytics.
Si tu mets tout ça dans ta méthode placeOrder(), tu mélanges logique métier et effets secondaires, ton code devient difficile à tester, à maintenir, et à étendre.
La solution Spring : les événements
Spring te permet de publier un événement et de laisser d’autres composants réagir sans les connaître.
public record OrderPlacedEvent(Order order) {}Mise en place de ton évènement
@Service
public class OrderService {
private final ApplicationEventPublisher eventPublisher;
public OrderService(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void placeOrder(Order order) {
// ... logique métier
eventPublisher.publishEvent(new OrderPlacedEvent(order));
}
}Réaction à l'évènement
@Component
public class EmailListener {
@EventListener
public void sendConfirmation(OrderPlacedEvent event) {
// Envoie un courriel
}
}
@Component
public class AuditListener {
@EventListener
public void logOrder(OrderPlacedEvent event) {
// Écrit dans les logs ou une table d’audit
}
}Si tu as besoin d'ajouter un nouveau comportement, tu n'as pas besoin de modifier
OrderService.
Attention aux pièges
- Les listeners synchrones partagent la même transaction que l’émetteur.
Si la transaction échoue, aucun effet ne doit persister.
- Les listeners asynchrones ne peuvent pas participer à la transaction car il y a
risque de divergence si tu modifies des données critiques.
Fonctionnalités avancées
Ajout de condition
@EventListener(condition = "#event.order.total > 1000")
public void notifyPremiumSupport(OrderPlacedEvent event) {
...
}
Il y a la possibilité d'imposer un ordre d'exécution
@Component
public class EmailListener {
@EventListener
@Order(1)
public void sendConfirmation(OrderPlacedEvent event) {
// Envoie un courriel
}
}
@Component
public class AuditListener {
@EventListener
@Order(2)
public void logOrder(OrderPlacedEvent event) {
// Écrit dans les logs ou une table d’audit
}
}
Détail technique concernant l'ordre
- Spring collecte tous les
@EventListener écoutant un événement donné. - Il les trie selon :La valeur de
@Order (plus petit = exécuté en premier).
Si aucune @Order n’est spécifiée, la valeur par défaut est
Ordered.LOWEST_PRECEDENCE (c’est-à-dire exécuté en dernier). - Le tri est strictement global au contexte applicatif,
pas local à la classe ou au package.Spring permet de mettre des conditions
Pourquoi l’utiliser ?
- Zéro dépendance externe (c’est dans Spring Core).
- Typé, testable, et lisible.
- Parfait pour les architectures modulaires ou les librairies réutilisables.
Il est possible d'utiliser spring modulith pour aller encore
plus loin dans la communication de vos modules de votre application monolith.
Ce n’est pas de la magie… c’est du bon design, rendu simple par Spring.
Aucun commentaire:
Enregistrer un commentaire