La anotación Spring @Qualifier

1. Información general

En este artículo, exploraremos en qué nos puede ayudar la anotación @Qualifier , qué problemas resuelve y cómo usarlo.

También explicaremos en qué se diferencia de la anotación @Primary y del cableado automático por nombre.

2. Necesidad de desambiguación del cableado automático

La anotación @Autowired es una excelente manera de hacer explícita la necesidad de inyectar una dependencia en Spring. Y aunque es útil, hay casos de uso en los que esta anotación por sí sola no es suficiente para que Spring comprenda qué bean inyectar.

De forma predeterminada, Spring resuelve las entradas conectadas automáticamente por tipo.

Si hay más de un bean del mismo tipo disponible en el contenedor, el marco arrojará NoUniqueBeanDefinitionException , lo que indica que hay más de un bean disponible para el cableado automático.

Imaginemos una situación en la que existen dos posibles candidatos para que Spring inyecte como colaboradores de beans en una instancia determinada:

@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 intentamos cargar FooService en nuestro contexto, el marco de Spring arrojará una NoUniqueBeanDefinitionException . Esto se debe a que Spring no sabe qué bean inyectar . Para evitar este problema, existen varias soluciones. La anotación @Qualifier es una de ellas.

3. Anotación @Qualifier

Al utilizar la anotación @Qualifier , podemos eliminar el problema de qué bean necesita inyectarse .

Revisemos nuestro ejemplo anterior y veamos cómo resolvemos el problema al incluir la anotación @Qualifier para indicar qué bean queremos usar:

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

Al incluir la anotación @Qualifier junto con el nombre de la implementación específica que queremos usar, en este ejemplo, Foo , podemos evitar la ambigüedad cuando Spring encuentra varios beans del mismo tipo.

Debemos tener en cuenta que el nombre de calificador que se utilizará es el declarado en la anotación @Component .

Tenga en cuenta que también podríamos haber utilizado la anotación @Qualifier en las clases de implementación del formateador , en lugar de especificar los nombres en sus anotaciones @Component , para obtener el mismo efecto:

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

4. @Qualifier vs @Primary

Hay otra anotación llamada @Primary que podemos usar para decidir qué bean inyectar cuando existe ambigüedad con respecto a la inyección de dependencia.

Esta anotación define una preferencia cuando están presentes varios beans del mismo tipo . El bean asociado con la anotación @Primary se utilizará a menos que se indique lo contrario.

Veamos un ejemplo:

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

En este ejemplo, ambos métodos devuelven el mismo tipo de empleado . El bean que inyectará Spring es el devuelto por el método tonyEmployee . Esto se debe a que contiene la anotación @Primary . Esta anotación es útil cuando queremos especificar qué bean de cierto tipo debe inyectarse por defecto .

Y en caso de que necesitemos el otro bean en algún punto de inyección, tendríamos que indicarlo específicamente. Podemos hacerlo a través de la anotación @Qualifier . Por ejemplo, podríamos especificar que queremos usar el bean devuelto por el método johnEmployee usando la anotación @Qualifier .

Vale la pena señalar que si las anotaciones @Qualifier y @Primary están presentes, entonces la anotación @Qualifier tendrá prioridad. Básicamente, @Primary define un valor predeterminado, mientras que @Qualifier es muy específico.

Veamos otra forma de usar la anotación @Primary , esta vez usando el ejemplo inicial:

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

En este caso, la anotación @Primary se coloca en una de las clases de implementación y eliminará la ambigüedad del escenario.

5. @Qualifier vs Autowiring por nombre

Otra forma de decidir entre varios beans cuando se realiza el cableado automático es utilizando el nombre del campo para inyectar. Este es el valor predeterminado en caso de que no haya otras sugerencias para Spring . Veamos un código basado en nuestro ejemplo inicial:

public class FooService { @Autowired private Formatter fooFormatter; }

En este caso, Spring determinará que el bean a inyectar es el FooFormatter ya que el nombre del campo coincide con el valor que usamos en la anotación @Component para ese bean.

6. Conclusión

Hemos descrito los escenarios en los que necesitamos eliminar la ambigüedad de qué beans inyectar. En particular, describimos la anotación @Qualifier y la comparamos con otras formas similares de determinar qué beans deben usarse.

Como de costumbre, el código completo de este artículo está disponible en GitHub.