19‐Annotation Autowiring and Qualifiers - JuhMaran/Java-with-Spring-Boot GitHub Wiki
44. Qualificadores (@Qualifier) – Visão Geral
Autowiring (Injeção Automática)
- Quando usamos injeção automática no Spring, ele tenta encontrar e injetar automaticamente um componente (
@Component) que implemente uma determinada interface. - Se houver apenas uma implementação da interface, tudo funciona bem.
- Mas... e se existirem várias implementações?
Exemplo com Múltiplos "Coach" (Treinadores)
Digamos que temos a interface Coach, e várias classes que a implementam:
@Component
public class CricketCoach implements Coach {
public String getDailyWorkout() {
return "Treine arremesso rápido por 15 minutos";
}
}
@Component
public class TrackCoach implements Coach {
public String getDailyWorkout() {
return "Corra uma prova intensa de 5km!";
}
}
@Component
public class BaseballCoach implements Coach {
public String getDailyWorkout() {
return "Pratique rebatidas por 30 minutos";
}
}
@Component
public class TennisCoach implements Coach {
public String getDailyWorkout() {
return "Treine seu voleio de backhand";
}
}
Problema: Múltiplas Implementações Encontradas
Se você tentar injetar um Coach assim:
private Coach myCoach;
O Spring não saberá qual classe usar, porque há quatro opções. O erro será algo como:
Erro: o construtor precisa de um único bean, mas foram encontrados 4:
- baseballCoach
- cricketCoach
- tennisCoach
- trackCoach
Solução: Use @Qualifier para Especificar
Para resolver esse problema, usamos a anotação @Qualifier, que diz ao Spring exatamente qual bean usar.
Exemplo com injeção via construtor:
@RestController
public class DemoController {
private Coach myCoach;
@Autowired
public DemoController(@Qualifier("cricketCoach") Coach myCoach) {
this.myCoach = myCoach;
}
@GetMapping("/dailyworkout")
public String getDailyWorkout() {
return myCoach.getDailyWorkout();
}
}
Explicação:
@Qualifier("cricketCoach"): indica que o Spring deve injetar o bean com IDcricketCoach.- O nome do bean é, por padrão, o nome da classe com a primeira letra em minúsculo:
CricketCoach→cricketCoach.
Você também poderia usar outros beans, como:
baseballCoachtrackCoachtennisCoach
Também Funciona com Injeção via Setter
Se estiver usando injeção por método setter, você também pode aplicar @Qualifier.
@Component
public class DemoController {
private Coach myCoach;
@Autowired
@Qualifier("cricketCoach")
public void setCoach(Coach myCoach) {
this.myCoach = myCoach;
}
}
Sobre a Anotação @Qualifier
A anotação @Qualifier é usada para ajudar o Spring a decidir qual bean deve ser injetado, quando há múltiplas opções disponíveis.
Ela pode ser usada em:
- Parâmetros de métodos
- Métodos setters
- Campos (atributos)
45. Qualifiers - Coding - Parte 1
Voltando para injeção via construtor
Vamos ajustar o controlador para usar injeção de dependência via construtor:
@RestController
public class DemoController {
private Coach myCoach;
@Autowired
public DemoController(Coach myCoach) {
this.myCoach = myCoach;
}
@GetMapping("/dailyworkout")
public String getDailyWorkout() {
return myCoach.getDailyWorkout();
}
}
Criando múltiplas implementações da interface Coach
Vamos criar várias classes que implementam a interface Coach. Cada classe representa um tipo diferente de treinador:
@Component
public class CricketCoach implements Coach {
public String getDailyWorkout() {
return "Treine arremesso rápido por 15 minutos";
}
}
@Component
public class TrackCoach implements Coach {
public String getDailyWorkout() {
return "Corra uma prova intensa de 5km!";
}
}
@Component
public class BaseballCoach implements Coach {
public String getDailyWorkout() {
return "Pratique rebatidas por 30 minutos";
}
}
@Component
public class TennisCoach implements Coach {
public String getDailyWorkout() {
return "Treine seu voleio de backhand";
}
}
46. Qualifiers - Coding - Parte 2
Problema: múltiplos beans do tipo Coach
Quando tentamos executar a aplicação, recebemos o seguinte erro:
Parameter 0 of constructor in com.juhmaran.springcoredemo.rest.DemoController required a single bean, but 4 were found:
- baseballCoach
- cricketCoach
- tennisCoach
- trackCoach
Isso acontece porque temos várias implementações da interface Coach, e o Spring não sabe qual delas deve injetar no controlador.
Solução: usar @Qualifier para especificar o bean
Para resolver esse problema, podemos usar a anotação @Qualifier e indicar qual implementação deve ser usada:
@RestController
public class DemoController {
private Coach myCoach;
@Autowired
public DemoController(@Qualifier("baseballCoach") Coach myCoach) {
this.myCoach = myCoach;
}
@GetMapping("/dailyworkout")
public String getDailyWorkout() {
return myCoach.getDailyWorkout();
}
}
Importante: o valor passado no @Qualifier deve ser o nome do bean, que por padrão é o nome da classe com a primeira letra minúscula. Exemplo:
- Classe
BaseballCoach→ Bean ID:baseballCoach - Classe
TrackCoach→ Bean ID:trackCoach
Testando diferentes implementações
Se alterarmos o @Qualifier para outro bean, o comportamento muda. Por exemplo:
// Usando o TrackCoach
@Qualifier("trackCoach")
Resultado no navegador:
"Corra uma prova intensa de 5km!"
// Usando o CricketCoach
@Qualifier("cricketCoach")
Resultado no navegador:
"Treine arremesso rápido por 15 minutos"
Conclusão
Com a anotação @Qualifier, conseguimos dizer ao Spring exatamente qual implementação usar, resolvendo o problema de ambiguidade quando existem múltiplos beans do mesmo tipo.
Essa abordagem é muito útil quando estamos trabalhando com injeção de dependências e queremos manter o controle sobre qual implementação está sendo usada.