A anotação Spring @Qualifier
1. Visão geral
Neste artigo, vamos explorarwhat the @Qualifier annotation can help us with, quais problemas ele resolve e como usá-lo.
Também explicaremos como ele é diferente da anotação@Primary e do autowiring por nome.
2. Necessidade de desambiguação da Autowire
A anotação@Autowired é uma ótima maneira de tornar explícita a necessidade de injetar uma dependência no Spring. E embora seja útil, há casos de uso para os quais essa anotação por si só não é suficiente para o Spring entender qual bean injetar.
Por padrão, o Spring resolve entradas automáticas por tipo.
If more than one bean of the same type is available in the container, the framework will throw NoUniqueBeanDefinitionException, indicando que mais de um bean está disponível para autowiring.
Vamos imaginar uma situação em que dois possíveis candidatos existem para que o Spring injete como colaboradores de bean em uma determinada instância:
@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;
}
Se tentarmos carregarFooService em nosso contexto, o framework Spring lançará umNoUniqueBeanDefinitionException. Isso ocorre porqueSpring doesn’t know which bean to inject. Para evitar esse problema, existem várias soluções. A anotação@Qualifier é uma delas.
3. @Qualifier Anotação
Usando a anotação@Qualifier, podemoseliminate the issue of which bean needs to be injected.
Vamos revisitar nosso exemplo anterior e ver como resolvemos o problema incluindo a anotação@Qualifier para indicar qual bean queremos usar:
public class FooService {
@Autowired
@Qualifier("fooFormatter")
private Formatter formatter;
}
Incluindo a anotação@Qualifier junto com o nome da implementação específica que queremos usar - neste exemplo,Foo - podemos evitar ambigüidade quando o Spring encontra vários beans do mesmo tipo.
Precisamos levar em consideração que o nome do qualificador a ser usado é aquele declarado na anotação@Component.
Observe que também poderíamos ter usado a anotação@Qualifier nas classes de implementaçãoFormatter, em vez de especificar os nomes em suas anotações@Component, para obter o mesmo efeito:
@Component
@Qualifier("fooFormatter")
public class FooFormatter implements Formatter {
//...
}
@Component
@Qualifier("barFormatter")
public class BarFormatter implements Formatter {
//...
}
4. @Qualifier vs@Primary
Há outra anotação chamada@Primary que podemos usar para decidir qual bean injetar quando há ambigüidade em relação à injeção de dependência.
Esta anotaçãodefines a preference when multiple beans of the same type are present. O bean associado à anotação@Primary será usado, a menos que indicado de outra forma.
Vamos ver um exemplo:
@Configuration
public class Config {
@Bean
public Employee johnEmployee() {
return new Employee("John");
}
@Bean
@Primary
public Employee tonyEmployee() {
return new Employee("Tony");
}
}
Neste exemplo, os dois métodos retornam o mesmo tipoEmployee. O bean que o Spring injetará é aquele retornado pelo métodotonyEmployee. Isso ocorre porque ele contém a anotação@Primary. Esta anotação é útil quando queremosspecify which bean of a certain type should be injected by default.
E caso necessitemos do outro bean em algum ponto da injeção, precisaríamos indicá-lo especificamente. Podemos fazer isso por meio da anotação@Qualifier. Por exemplo, poderíamos especificar que queremos usar o bean retornado pelo métodojohnEmployee usando a anotação@Qualifier.
É importante notar queif both the @Qualifier and @Primary annotations are present, then the @Qualifier annotation will have precedence. Basicamente,@Primary define um padrão, enquanto@Qualifier é muito específico.
Vamos ver outra maneira de usar a anotação@Primary, desta vez usando o exemplo inicial:
@Component
@Primary
public class FooFormatter implements Formatter {
//...
}
@Component
public class BarFormatter implements Formatter {
//...
}
In this case, the @Primary annotation is placed in one of the implementing classese eliminará a ambiguidade do cenário.
5. @Qualifier vs Autowiring por nome
Outra maneira de decidir entre vários beans quando a fiação automática é usando o nome do campo para injetar. This is the default in case there are no other hints for Spring. Vamos ver alguns códigos com base em nosso exemplo inicial:
public class FooService {
@Autowired
private Formatter fooFormatter;
}
Nesse caso, o Spring determinará que o bean a ser injetado é oFooFormatter, pois o nome do campo corresponde ao valor que usamos na anotação@Component para aquele bean.
6. Conclusão
Descrevemos os cenários em que precisamos eliminar a ambigüidade de quais beans injetar. Em particular, descrevemos a anotação@Qualifier e a comparamos com outras maneiras semelhantes de determinar quais beans precisam ser usados.
Como de costume, o código completo deste artigo está disponívelover on GitHub.