L'annotation Spring @Qualifier

1. Vue d'ensemble

Dans cet article, nous explorerons ce que l' annotation @Qualifier peut nous aider , les problèmes qu'elle résout et comment l'utiliser.

Nous expliquerons également en quoi il est différent de l' annotation @Primary et du câblage automatique par nom.

2. Autowire Besoin de clarifier les ambiguïtés

L' annotation @Autowired est un excellent moyen de rendre explicite la nécessité d'injecter une dépendance dans Spring. Et bien que cela soit utile, il existe des cas d'utilisation pour lesquels cette annotation seule ne suffit pas à Spring pour comprendre quel bean injecter.

Par défaut, Spring résout les entrées auto-câblées par type.

Si plusieurs bean du même type sont disponibles dans le conteneur, le framework lèvera NoUniqueBeanDefinitionException , indiquant que plus d'un bean est disponible pour le câblage automatique.

Imaginons une situation dans laquelle deux candidats possibles existent pour que Spring s'injecte en tant que collaborateurs bean dans une instance donnée:

@Component("fooFormatter") public class FooFormatter implements Formatter { public String format() { return "foo"; } } @Component("barFormatter") public class BarFormatter implements Formatter { public String format() { return "bar"; } } @Component public class FooService { @Autowired private Formatter formatter; }

Si nous essayons de charger FooService dans notre contexte, le framework Spring lèvera une NoUniqueBeanDefinitionException . C'est parce que Spring ne sait pas quel haricot injecter . Pour éviter ce problème, il existe plusieurs solutions. L' annotation @Qualifier en fait partie.

3. Annotation @Qualifier

En utilisant l' annotation @Qualifier , nous pouvons éliminer le problème de savoir quel bean doit être injecté .

Revenons à notre exemple précédent et voyons comment nous résolvons le problème en incluant l' annotation @Qualifier pour indiquer quel bean nous voulons utiliser:

public class FooService { @Autowired @Qualifier("fooFormatter") private Formatter formatter; }

En incluant l' annotation @Qualifier avec le nom de l'implémentation spécifique que nous voulons utiliser - dans cet exemple, Foo - nous pouvons éviter toute ambiguïté lorsque Spring trouve plusieurs beans du même type.

Nous devons prendre en compte le fait que le nom du qualificatif à utiliser est celui déclaré dans l' annotation @Component .

Notez que nous aurions pu également utiliser l' annotation @Qualifier sur les classes d'implémentation du formateur , au lieu de spécifier les noms dans leurs annotations @Component , pour obtenir le même effet:

@Component @Qualifier("fooFormatter") public class FooFormatter implements Formatter { //... } @Component @Qualifier("barFormatter") public class BarFormatter implements Formatter { //... } 

4. @Qualifier vs @Primary

Il existe une autre annotation appelée @Primary que nous pouvons utiliser pour décider quel bean injecter en cas d'ambiguïté concernant l'injection de dépendances.

Cette annotation définit une préférence lorsque plusieurs beans du même type sont présents . Le bean associé à l' annotation @Primary sera utilisé sauf indication contraire.

Voyons un exemple:

@Configuration public class Config { @Bean public Employee johnEmployee() { return new Employee("John"); } @Bean @Primary public Employee tonyEmployee() { return new Employee("Tony"); } }

Dans cet exemple, les deux méthodes renvoient le même type Employee . Le bean que Spring injectera est celui retourné par la méthode tonyEmployee . En effet, il contient l' annotation @Primary . Cette annotation est utile lorsque nous voulons spécifier quel bean d'un certain type doit être injecté par défaut .

Et au cas où nous aurions besoin de l'autre bean à un point d'injection, nous aurions besoin de l'indiquer spécifiquement. Nous pouvons le faire via l' annotation @Qualifier . Par exemple, nous pourrions spécifier que nous voulons utiliser le bean retourné par la méthode johnEmployee en utilisant l' annotation @Qualifier .

Il convient de noter que si les annotations @Qualifier et @Primary sont présentes, l' annotation @Qualifier aura la priorité. Fondamentalement, @Primary définit une valeur par défaut, tandis que @Qualifier est très spécifique.

Voyons une autre façon d'utiliser l' annotation @Primary , cette fois en utilisant l'exemple initial:

@Component @Primary public class FooFormatter implements Formatter { //... } @Component public class BarFormatter implements Formatter { //... } 

Dans ce cas, l' annotation @Primary est placée dans l'une des classes d'implémentation et éliminera l' ambiguïté du scénario.

5. @Qualifier vs Autowiring par nom

Une autre façon de choisir entre plusieurs beans lors du câblage automatique consiste à utiliser le nom du champ à injecter. C'est la valeur par défaut au cas où il n'y aurait pas d'autres indices pour Spring . Voyons du code basé sur notre exemple initial:

public class FooService { @Autowired private Formatter fooFormatter; }

Dans ce cas, Spring déterminera que le bean à injecter est le FooFormatter car le nom du champ correspond à la valeur que nous avons utilisée dans l' annotation @Component pour ce bean.

6. Conclusion

Nous avons décrit les scénarios dans lesquels nous devons lever l'ambiguïté sur les beans à injecter. En particulier, nous avons décrit l' annotation @Qualifier et l' avons comparée à d'autres méthodes similaires pour déterminer quels beans doivent être utilisés.

Comme d'habitude, le code complet de cet article est disponible à l'adresse over sur GitHub.