Injection de dépendances (Dependency Injection) en Java : guide complet

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : Pourquoi Dependency Injection est un must-have pour le développeur Java

Tout développeur Java rencontre tôt ou tard le problème du couplage fort du code. Lorsqu'une classe crée directement des instances d'autres classes, le système devient fragile, difficile à tester et à modifier. La solution à ce problème est Dependency Injection (DI). C'est l'un des principes clés du développement moderne, qui est à la base de frameworks comme Spring et Jakarta EE.

Dans cet article, nous allons voir ce qu'est la DI, en quoi elle diffère de l'IoC (Inversion of Control), examiner les trois principales façons d'injecter des dépendances en Java avec des exemples de code concrets, et discuter pourquoi ce pattern est essentiel pour créer des applications maintenables.



Qu'est-ce que Dependency Injection et Inversion of Control ?

Avant de passer au code, il est important de comprendre deux concepts fondamentaux.

Inversion of Control (IoC) est un principe général selon lequel le flux de contrôle du programme est transféré à un framework ou un conteneur externe. Au lieu que le code décide lui-même quand créer des objets et appeler des méthodes, c'est un système externe qui s'en charge.

Dependency Injection est une implémentation concrète du principe IoC. C'est un pattern dans lequel un objet reçoit ses dépendances (les autres objets dont il dépend) de l'extérieur, au lieu de les créer lui-même.

En termes simples, au lieu que la classe Car crée elle-même le moteur (new Engine()), elle reçoit un moteur prêt à l'emploi via son constructeur ou un setter. Cela rend la classe Car indépendante de l'implémentation spécifique de Engine.



Trois façons d'injecter des dépendances en Java

En Java, il existe trois principales façons d'implémenter la DI. Examinons chacune d'elles à l'aide d'un exemple simple de système de notifications.



1. Injection par constructeur (Constructor Injection)

C'est la méthode la plus recommandée et la plus sûre. Les dépendances sont transmises via le constructeur de la classe. Cela garantit que l'objet ne sera jamais créé dans un état invalide, car toutes les dépendances nécessaires sont obligatoires.

// Interface pour le service de notificationspublic interface MessageService {    void sendMessage(String message, String recipient);}

// Implémentation pour Emailpublic class EmailService implements MessageService { @Override public void sendMessage(String message, String recipient) { System.out.println("Email sent to " + recipient + ": " + message); }}

// Classe qui utilise le service de notificationspublic class NotificationSender { private final MessageService service; // Dépendance

// Injection par constructeur public NotificationSender(MessageService service) { this.service = service; }

public void notifyUser(String user, String msg) { this.service.sendMessage(msg, user); }}

// Utilisationpublic class Main { public static void main(String[] args) { MessageService emailService = new EmailService(); NotificationSender sender = new NotificationSender(emailService); // DI sender.notifyUser("user@example.com", "Hello!"); }}


2. Injection par setter (Setter Injection)

Cette méthode est utilisée lorsque la dépendance n'est pas obligatoire ou peut être modifiée après la création de l'objet. La dépendance est transmise via une méthode setter publique.

public class NotificationSenderWithSetter {    private MessageService service; // Dépendance non obligatoire

// Setter pour l'injection public void setMessageService(MessageService service) { this.service = service; }

public void notifyUser(String user, String msg) { if (service != null) { this.service.sendMessage(msg, user); } else { System.out.println("No service configured!"); } }}

// Utilisation

Blogs

Book Recommendations