Injection de dépendances de constructeur au printemps

1. Introduction

L'un des principes de développement les plus importants de la conception de logiciels modernes est sans doute l' injection de dépendances (DI) qui découle tout naturellement d'un autre principe d'une importance cruciale: la modularité.

Cet article explorera un type spécifique de technique DI appelée Injection de dépendances basée sur le constructeur dans Spring - ce qui signifie simplement que les composants requis sont passés dans une classe au moment de l'instanciation.

Pour commencer, nous devons importer la dépendance de contexte de printemps dans notre pom.xml :

 org.springframework spring-context 5.2.8.RELEASE 

Ensuite, nous devons créer un fichier de configuration . Ce fichier peut être soit un POJO, soit si vous préférez, un fichier XML.

2. Configuration basée sur les annotations

Le fichier de configuration Java ressemble à peu près à un objet Java ordinaire avec quelques annotations supplémentaires:

@Configuration @ComponentScan("com.baeldung.constructordi") public class Config { @Bean public Engine engine() { return new Engine("v8", 5); } @Bean public Transmission transmission() { return new Transmission("sliding"); } } 

Ici, nous utilisons des annotations pour informer Spring runtime que cette classe est un fournisseur de définitions de bean ( annotation @Bean ) et qu'une analyse de contexte pour des beans supplémentaires doit être effectuée dans le package com.baeldung.spring . Ensuite, nous définissons une classe Car :

@Component public class Car { @Autowired public Car(Engine engine, Transmission transmission) { this.engine = engine; this.transmission = transmission; } }

Spring rencontrera notre classe Car lors d'une analyse de package et initialisera son instance en appelant le constructeur annoté @Autowired .

Les instances du moteur et de la transmission seront obtenues en appelant les méthodes annotées @Bean de la classe Config . Enfin, nous devons amorcer un ApplicationContext en utilisant notre configuration POJO:

ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); Car car = context.getBean(Car.class);

3. Injection de constructeur implicite

Depuis le printemps 4.3, les classes avec un seul constructeur peuvent omettre l' annotation @Autowired . Un petit peu de commodité et de retrait passe-partout!

En plus de cela, à partir de 4.3 également, l'injection basée sur le constructeur peut être exploitée dans les classes annotées @Configuration . Et oui, si une telle classe n'a qu'un seul constructeur, l' annotation @Autowired peut également être omise.

4. Configuration basée sur XML

Une autre façon de configurer l'environnement d'exécution Spring avec l'injection de dépendances basée sur un constructeur consiste à utiliser un fichier de configuration XML:

Notez que constructor-arg peut accepter une valeur littérale ou une référence à un autre bean et qu'un index et un type explicites facultatifs peuvent être fournis. Les attributs de type et d' index peuvent être utilisés pour résoudre l'ambiguïté (par exemple, si un constructeur prend plusieurs arguments du même type).

L' attribut name peut également être utilisé pour la correspondance de variables xml à java, mais votre code doit être compilé avec l'indicateur de débogage activé.

Un contexte d'application Spring, dans ce cas, doit être amorcé à l'aide de ClassPathXmlApplicationContext :

ApplicationContext context = new ClassPathXmlApplicationContext("baeldung.xml"); Car car = context.getBean(Car.class);

5. Avantages et inconvénients

L'injection de constructeur présente quelques avantages par rapport à l'injection de champ.

Le premier avantage est la testabilité. Supposons que nous allons tester unitaire un bean Spring qui utilise l'injection de champ:

public class UserService { @Autowired private UserRepository userRepository; }

Lors de la construction d'une instance UserService , nous ne pouvons pas initialiser l' état userRepository . Le seul moyen d'y parvenir est d'utiliser l'API Reflection, qui rompt complètement l'encapsulation. De plus, le code résultant sera moins sûr qu'un simple appel de constructeur.

De plus, avec l' injection de champ, nous ne pouvons pas appliquer les invariants au niveau de la classe.Il est donc possible d'avoir une instance UserService sans userRepository correctement initialisé . Par conséquent, nous pouvons rencontrer des NullPointerException aléatoires ici et là. De plus, avec l'injection de constructeur, il est plus facile de créer des composants immuables.

De plus, l' utilisation de constructeurs pour créer des instances d'objet est plus naturelle du point de vue de la POO.

D'un autre côté, le principal inconvénient de l'injection de constructeur est sa verbosité surtout lorsqu'un bean a une poignée de dépendances. Parfois, cela peut être une bénédiction déguisée, car nous pouvons essayer de réduire au minimum le nombre de dépendances.

6. Conclusion

Ce didacticiel rapide a présenté les bases de deux manières distinctes d'utiliser l' injection de dépendances basée sur le constructeur à l'aide du framework Spring.

L' implémentation complète de ce tutoriel est disponible à l'adresse over sur GitHub.