Spring Boot : écrire le serveur (école d'ingénieur) · Chapitre 2 · Exercice de TD
Un cycle de dépendances
Injection de dépendances et configuration · niveau 2
Énoncé
Dans le projet code/ch2/erreurs/cycle, PanierService reçoit un StockService, qui reçoit un PanierService. Lancer l'application et lire le rapport. Pourquoi Spring ne peut-il pas créer ces deux beans ? Proposer une nouvelle répartition des responsabilités qui supprime le cycle : le panier réserve des exemplaires auprès du stock.
Corrigé
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| panierService defined in URL [jar:nested: /livre/code/ch2/erreurs/cycle/target/cycle-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/fr/librairie/PanierService.class]
↑ ↓
| stockService defined in URL [jar:nested: /livre/code/ch2/erreurs/cycle/target/cycle-0.0.1-SNAPSHOT.jar/!BOOT-INF/classes/!/fr/librairie/StockService.class]
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
Pour créer PanierService, il faut d'abord un StockService ; pour créer celui-ci, il faut d'abord un PanierService : avec l'injection par constructeur, aucun des deux ne peut être construit en premier. Spring le détecte et s'arrête (le schéma du rapport dessine le cycle). La bonne correction n'est pas technique : un cycle trahit des responsabilités mal réparties. Le stock n'a pas à connaître le panier ; c'est le panier qui réserve auprès du stock :
@Service
public class PanierService {
private final StockService stock;
public PanierService(StockService stock) {
this.stock = stock;
}
public String ajouter(String isbn, int quantite) {
return stock.reserver(isbn, quantite) ? "ajouté" : "stock insuffisant";
}
}
/** Le stock ne connaît plus le panier : le cycle est rompu. */
@Service
public class StockService {
private final Map<String, Integer> stock = new ConcurrentHashMap<>(Map.of("9782956300014", 12));
public synchronized boolean reserver(String isbn, int quantite) {
int dispo = stock.getOrDefault(isbn, 0);
if (dispo < quantite) {
return false;
}
stock.put(isbn, dispo - quantite);
return true;
}
}
synchronized rend la réservation indivisible : deux requêtes simultanées ne peuvent pas réserver le même dernier exemplaire.
100 % gratuit
La suite du chapitre est sur Adloun
- 10 autres exercices corrigés dans ce chapitre
- Les 2 QCM du chapitre, le premier sans compte
- Le tuteur, qui guide pas à pas sans donner la réponse
Sans compte : le cours et le premier QCM. Exercices et tuteur : inscription gratuite en 30 secondes, sans carte bancaire.