O Spring conta com a feature do IOC container que nos provê várias anotações para que possamos dizer a ele qual método ou classe ele irá gerenciar, essas anotações são importantes para que possamos aplicar conceitos de Design Patterns.
Por exemplo, em alguns códigos usando Spring é comum encontrarmos uma classe em que se é instanciado uma interface e essa interface contém uma implementação. Como no exemplo abaixo onde a classe CurriculoService
instancia uma interface GeraCurriculo
Mas e se acontecesse dessa interface ter duas implementações como o caso abaixo, o que aconteceria?
O Spring lançaria a exceção NoUniqueBeanDefinitionException, por quê? Porque o Spring não seria capaz de determinar qual classe utilizar, não basta dizer ao Spring o que gerenciar, em alguns cenários será necessário dizer a ele qual implementação usar. Para isso separei três maneiras das quais podemos dizer ao Spring qual implementação utilizar.
Através da anotação Primary
O simples ato de anotar uma classe com @Primary
irá dar prioridade aquela classe em caso de haver múltiplas implementações ou Beans, por exemplo caso eu queira que a classe GeraCurriculoWordService
fosse chamada toda vez que eu proveja a interface GeraCurriculo
basta apenas isso:
Através da anotação @Qualifier
Com essa anotação podemos "nomear" as classes e ao prover uma interface fazer referencia a ela, ainda usando nosso exemplo poderíamos dar prioridade para nossa classe GeraCurriculoPdfService
da seguinte maneira.
Primeiramente anotamos nossa classe com o @Qualifier
e passamos como parâmetro um identificador, no caso aqui selecionei o próprio nome da classe:
E por fim, ao provermos nossa interface podemos dizer para usar a implementação em especifico também com a anotação @Qualifier
como no exemplo abaixo:
Note que desta maneira não ficamos preso a uma implementação como na anotação @Primary
com o @Qualifier
podemos ter mais dinamismo ao prover nossa interface e decidir a implementação. Isso não anula a @Primary
mesmo usando qualifiers ainda poderíamos deixar uma implementação como default em caso de não especificarmos nenhuma classe ao provermos a interface.
Selecionando a implementação dinamicamente
Vamos supor agora que o usuário que está usando o sistema selecionará o formato de seu currículo, eu preciso ter uma maneira de selecionar a implementação em runtime.
Para isso podemos usar um dos recursos menos conhecidos do Spring. Como vimos no início do artigo quando temos apenas uma implementação de uma interface o Spring sabe injetar automaticamente essa implementação quando necessário. Mas o Spring também nos dá a capacidade de coletar todos os beans que são implementações de uma interface específica. Assim podemos mapear as implementações para usá-las posteriormente como no exemplo abaixo:
Veja que no construtor da classe passamos como parâmetro uma lista da interface, o Spring no entanto coleta todas as implementações existentes e popula automaticamente essa lista para nós, tornando fácil mapear da maneira como queremos, como foi feito na linha 8 do exemplo acima onde mapeamos o tipo do arquivo que a implementação ligado a própria implementação.
Para resolvermos o problema citado sobre gerar um currículo dinamicamente poderíamos fazer assim:
Veja que agora a classe CurriculoService
está injetando a classe onde mapeamos a lista de implementações da interface GeraCurriculo
. Então no método da linha 8 getCurriculo
podemos nos preocupar em passar apenas o tipo do arquivo que queremos em vez de termos métodos para cada implementação, na linha 9 selecionamos a implementação que bate com o parâmetro informado e por fim temos acesso a nossa implementação e seus métodos.
Em resumo as anotações @Primary
e @Qualifier
são úteis quando temos várias implementações e precisamos selecionar uma em específico tendo a anotação @Qualifier
nos permitindo maior especificidade. Vimos também que o Spring oferece uma abordagem mais dinâmica através da coleta de todas as implementações de uma interface, permitindo que você escolha qual implementação usar em tempo de execução. Isso é útil quando você precisa selecionar a implementação com base em informações do usuário ou em condições variáveis.
Caso queira ver a implementação do código para selecionar uma classe dinamicamente você pode acessar nesse link do github
Top comments (0)