Duvida Spring @Autowired/@Inject

Estou começando estudos com Spring e fiquei em duvida no seguinte ponto.

Antes de conhecer o Spring a Injeção de dependência eu fazia via construtor, exemplo :

private IDAO dao;

public TesteBusiness(IDAO idao) {
		this.dao = idao;
}

Quem fosse criar uma instancia desse Business iria mandar no construtor qual implementação de IDAO iria precisar ser usado.

Agora com o Spring ficou :

@Autowired
private IDAO dao;

public TesteBusiness() {

} 

Não consigo ver uma forma de o spring saber se é pra injetar a implementação X ou Y da interface IDAO.

É possivel ?
Ou vou ter que criar sempre uma variavel da classe que implementa a interface :

@Autowired
private TesteDAO dao;

public TesteBusiness() {

}

Mas se for assim, não fere o principio do baixo acoplamento ?

Desde ja agradeço.
Vlw.

Nesse caso, você terá que usar Qualifiers. Uma anotação que específica qual implementação será usada:

@Autowired
@Qualifier("testeDAO")
private IDAO dao;

Mas isso nao é a mesma coisa que criar a variavel do tipo especifico:

@Autowired
private TesteDAO dao;

public TesteBusiness() {

}

E se eu quiser usar TesteDAO2 por exemplo ?

Não seria, pois definindo a variável assim:

@Autowired
private TesteDAO dao;

vai ficar realmente acoplado. E se definir pela interface:

@Autowired
@Qualifier("testeDAO")
private IDAO dao;

Não haverá acoplamento, pois a instância correta será injetada pelo spring usando o qualifier. E você ainda pode ter N daos injetados:

@Autowired
@Qualifier("aaaDAO")
private IDAO aaaDao;

@Autowired
@Qualifier("bbbDAO")
private IDAO bbbDao;

@Autowired
@Qualifier("cccDAO")
private IDAO cccDao;

Mas pra cada implementação preciso ter uma variavel diferente ?

Assim não fere o baixo acoplamento ?

Antes de usar o Spring eu tinha uma unica variavel do tipo IDAO que era recebida no construtor de acordo com o que era mandado da classe que faria o invoker desse business a variavel seria da implementação que eu precisava.

Mas ai depende. Sua classe business vai usar um ou mais DAOs para realizar a lógica de negócio. Pois quando a mesma for chamada e ela for realizar vários acessos ao banco, todos os DAOs envolvidos precisam estar disponíveis.

Então, não é que vai usar varios Daos na verdade dependendo da regra de negocio seria um dao x ou y, mas ambos implementam a mesma interface. Preciso ter um objeto pra cada implementação ou consigo usar uma unica, para o proprio spring de alguma forma saber qual implementação ele ira injetar ?

O Spring vai buscar a classe que implementa esta interface no caso você tem que ter apenas uma classe que implementa esta interface para não ter problemas com o Spring

Entendi.
Então a grande vantagem do Spring IOC é o gerencimento dos beans, mas o preço é perda do polimorfismo?

Como assim perda do polimorfismo?

hahaha acho q entendi a dúvida dele, porém não sei responder.

Acontece, que antes ele recebia as dependências pelo construtor, porém imagino q ele passava-as na mão.
Então ele tinha uma dependência da Interface X, e qdo chamasse a classe podia passar qqer implementação conforme a necessidade.

Porém usando o Spring ele acaba tendo que fixar a implementação específica através do Qualifier …

Pelo menos foi o que entendi xD

1 curtida

Isso mesmo.
E não consegui encontrar um jeito de fazer isso com Spring.

Oi @leo_vermont,

É possível fazer isso com spring, mas pra escolher a melhor forma, seria necessário mais informaçoes sobre seu caso específico.

De forma geral, eu geralmente prefiro colocar a anotaçao Autowired direto no construtor ao invés de colocar no atributo. Voce continua usando spring normalmente, mas a classe continua declarando suas dependencias explicitamente para o mundo.

Colocaria um exemplo aqui mas notei que nao sei mais colocar código no fórum novo :blush:

Voce diz que quer usar diferentes implementaçoes dependendo da sua lógica de negócios, algumas sugestoes:

  • Se for apenas implementacao para testes, na hora de definir o contexto do spring, voce pode apontar uma implmentaçao para produçao e outra para testes para sua interface IDAO

  • Se for realmente dinamico, voce pode controlar a criacao da sua TesteBusiness no seu próprio código, sem fazer o spring controlar o ciclo de vida do seu componente.

De qualquer forma, forneça mais detalhes do que precisa exatamente.

Na verdade não tenho um caso especifico ainda, estou começando a estudar o Spring e me peguei com essa duvida pois antes de conhecer o Spring eu fazia a injeção de dependência via construtor recebendo um objeto do tipo generio e quem fosse usar a classe mandaria no new da classe a implementação que precisaria. Todos exemplos que tinha visto até agora a anotação de injeção @Autowired ou @Inject estava direto na definicão da variavel, mas voce disse agora que da pra ser no construtor, acredito que > isso resolve o problema.

Se eu colocar por exemplo a anotação no contrutor :

public class Teste{

private IDAO idao;

@AutoWired
public Teste(IDAO idao){
this.idao = idao;
}
}

Assim a classe que iria fazer o invoker dessa classe teste faria assim:

public static void main(String[] args){

Teste teste = new Teste(new PessoaDao());
}

Assim o spring gerenciaria esse Bean, mesmo eu dando new ?

Nao, o spring nao gerenciaria. Quem ficaria responsável por isso seria a classe que chama a Teste.

Os beans gerenciados pelo spring, por default sao singleton (apenas uma instancia), entao nao é o comportamento mais comum que a dependencia mude a cada chamada.
Geralmente se a implementaçao mudaria a cada chamada, você poderia passar esse dao direto no método, ao invés do construtor. Ou criar várias instancias únicas do seu bean Teste, uma para cada tipo de dependencia. Depende muito do caso real.

Mas a resposta simples é que nesse caso o spring pode mais te atrapallhar do que te ajudar.

Mas fazendo assim eu entendo que eu estou ferindo o principio do baixo acoplamento, pois o fato de a variavel ser do tipo da interface e o Spring que injetar a implementação que vai ser usada não muda o fato de que a classe vai ser dependente de uma implementação x da minha interface, pois o Spring vai sempre injetar a mesma implementação.

Ou estou errado ?

Sim, a primeira vista pode parecer que sim. Mas você ainda tem possibilidade de passar diferentes implementaçoes, só muda o “onde” você decide isso.

No meu caso, costumo usar o construtor dos beans gerenciados pelo spring mais como uma configuraçao e os elementos mais dinamicos, passo diretamente na chamada de métodos.

Há formas mais dinamicas de se fazer isso dentro do prório spring (factory methods, por exemplo), mas como eu disse no começo, tudo depende da sua real necessidade.

Voce consegue me mostrar um exemplo do uso no construtor que voce falou ?

Como a minha criatividade está baixa, vamos fazer o contrário: me dá um caso de uso real que esteja pensando, onde faça sentido usar diferentes implementaçoes… daí eu tento converter para usar no spring.

1 curtida

Um caso que eu imagino que possa ser necessário é por exemplo, eu tenho uma interface Idao e 2 daos diferentes que implementam essa interface, SGBDDao e FileDAO. Agora imagine que um único business poderia ser usado esses 2 Daos, dependendo da regra de negócio. Sem o Spring eu receberia no construtor da business uma.instancia de Idao e quem fosse instanciar a business passaria qual das 2 implementaçoes seria usada e com o polimorfismo a mesma variável de instância idao seriviria pra qualquer implementação dela. Como eu conseguiria fazer isso com o Spring?