C'est le mecanisme central de Spring. Une fois compris, tout le reste devient
limpide.
1. Le probleme
public class EtudiantController {
// le controleur fabrique lui-meme ses dependances
private EtudiantService service = new EtudiantService(new EtudiantRepository());
}
Ce code fonctionne, mais il pose trois problemes : le controleur est fortement
couple a une implementation precise, il est difficile a tester (impossible
de substituer un faux service), et la moindre modification du constructeur se propage partout.
2. La solution : l'inversion de controle
Vous ne creez plus vos objets : vous les demandez, et Spring les fournit.
@RestController
public class EtudiantController {
private final EtudiantService service;
public EtudiantController(EtudiantService service) {
this.service = service;
}
}
Spring voit le constructeur, cherche un EtudiantService dans son conteneur, et le passe
automatiquement. C'est l'injection par constructeur, la forme recommandee.
3. Qu'est-ce qu'un bean ?
Un bean est simplement un objet gere par Spring : c'est lui qui le cree, le
configure et le fournit a ceux qui en ont besoin.
Annotation
A poser sur
@Component
Un composant generique
@Service
Une classe de logique metier
@Repository
Une classe d'acces aux donnees
@Controller
Un controleur web (pages)
@RestController
Un controleur REST (JSON)
Techniquement, @Service et @Repository sont des @Component.
Les distinguer rend simplement le role de chaque classe evident a la lecture.
4. Un exemple complet
@Repository
public class EtudiantRepository {
private final List<Etudiant> etudiants = new ArrayList<>();
public List<Etudiant> findAll() {
return etudiants;
}
public void save(Etudiant e) {
etudiants.add(e);
}
}
@Service
public class EtudiantService {
private final EtudiantRepository repository;
public EtudiantService(EtudiantRepository repository) {
this.repository = repository;
}
public List<Etudiant> listerAdmis() {
return repository.findAll().stream()
.filter(e -> e.getMoyenne() >= 10)
.toList();
}
}
@RestController
@RequestMapping("/etudiants")
public class EtudiantController {
private final EtudiantService service;
public EtudiantController(EtudiantService service) {
this.service = service;
}
@GetMapping("/admis")
public List<Etudiant> admis() {
return service.listerAdmis();
}
}
Chaque couche ne connait que la suivante. Spring assemble le tout au demarrage.
5. Les trois formes d'injection
Forme
Avis
Constructeur
Recommandee. Permet le final, facilite les tests, rend les dependances visibles
Setter
Acceptable pour une dependance facultative
Champ (@Autowired)
A eviter : masque les dependances et complique les tests
Depuis Spring 4.3, @Autowired est inutile sur un constructeur unique : Spring le detecte
seul.
6. Les portees
Portee
Signification
singleton
Une seule instance pour toute l'application : par defaut
prototype
Une nouvelle instance a chaque demande
request
Une instance par requete HTTP
Consequence a retenir : un bean singleton est partage. N'y stockez pas d'etat lie a
un utilisateur, sous peine de melanger les donnees entre visiteurs.
7. Les erreurs frequentes
NoSuchBeanDefinitionException : la classe n'a pas d'annotation, ou
se trouve hors du package scanne
Deux implementations d'une meme interface : Spring ne sait laquelle choisir.
Utilisez @Primary ou @Qualifier
Dependance circulaire : A a besoin de B qui a besoin de A. C'est le signe d'un
decoupage a revoir
A retenir
Vous ne creez pas vos objets, vous les demandez
Un bean est un objet gere par Spring
Preferez toujours l'injection par constructeur
Un singleton est partage : pas d'etat utilisateur dedans
Exercices d'application
Exercice 1. Trois couchesCreez CoursRepository, CoursService et CoursController avec les bonnes annotations. Faites remonter une liste de cours jusqu'a une route REST.
Exercice 2. Provoquer l'erreurRetirez l'annotation @Service de votre service et relancez. Lisez le message d'erreur et expliquez-le.
Exercice 3. Deux implementationsCreez une interface Notification avec deux implementations (mail et SMS). Faites choisir Spring avec @Primary, puis avec @Qualifier.
Cherchez avant de regarder la solution : c'est en butant sur les difficultes que l'on progresse.
Questions / Réponses
Aucune question. Soyez le premier à poser une question.