Injeção de Dependências com Spring
Tags: java, spring
Published: 2021-02-03 01:18:08

### Visão Geral

Na busca de melhorar a manutenção e atualização de projetos,  princípios como a inversão de controle (IOC) são ferramentas poderosas. A injeção de dependências é uma das formas de realizar a IOC. Sua utilização tira da raiz as dependências do projeto, esta prática tem boa sinergia com outras metodologias que compartilham dos mesmos objetivos, veremos na prática sua utilização de forma simples e sua aplicação ao utilizar Spring.

## Injeção de dependências e injeções médicas

Olhando inicialmente pode parecer estranho uma analisar uma relação além do evidente jogo de palavras entre injeções médicas e injeção de dependências, mas se visualizado da forma correta, pode ajudar na compreensão do assunto.

<b>Injeção de dependências</b>, trata-se de <i><b>design pattern</b> que visa inserção externa de dependência afim de diminuir o acoplamento de uma aplicação, afim de diminuir o erros, retrabalho e simplificar a implementação de novas atribuições ao projeto</i>. Numa primeira vista pode parecer um pouco confuso, talvez um bom exemplo te ajude a entender melhor, aí que entra como a medicina e a tão aguardada vacina do Covid-19 se relaciona com o assunto. 

Vacinas funcionam de diversas formas diferentes, pode ser feita com o vírus inativo, enfraquecido ou de forma sintética com mRNA. A forma que ela funciona não faz muita diferença para nós, afinal, nosso sistema imunológico já sabe exatamente o que fazer ao entrar em contato com o produto da vacina. 
<b>É exatamente a mesma ideia da injeção de dependências! </b> A atribuição pode ser de formas diferentes e essas diferenças <i>não vão alterar a raiz principal do nosso projeto.</i> 

## Mãos na massa

Vamos aplicar isto agora, através de um projeto simples. 
Temos inicialmente duas pessoas, Antônio com 67 anos e Maria com 80, ambos foram chamados para receber as doses da vacina de COVID-19 e cada um recebeu uma vacina de origem distinta. 

Para representa-los usaremos a Classe <i>Pessoa</i>, com os atributos nome e idade, e seus respectivos <b>getter</b> e <b>setter</b>.

```java
package vacina.di.model; 

public class Pessoa { 
private String nome; 
private int idade; 
 
public Pessoa(String nome, int idade) { 
	this.nome = nome; 
	this.idade = idade; 
} 

public String getNome() { 
	return nome; 
} 
public int getIdade() { 
	return idade; 
} 
} 
```


Para serem vacinados ambos foram ao SUS, um serviço público que aplica as vacinas, chamaremos este serviço de <i>VacinaService</i>, nele está a função de fazer com que as pessoas recebam a vacina. E claramente, para que eles sejam vacinados é necessário que exista uma <i>vacina</i>, que será um atributo desta classe. Isso é representado através da classe <i>VacinaService</i>: 

 
```java
package vacina.di.infrastructure.repository; 
import vacina.di.domain.repository.Vacina; 
import vacina.di.model.Pessoa; 
  
public class VacinaService { 
	private Vacina vacina; 
	public VacinaService(Vacina vacina) { 
		this.vacina = vacina; 
		} 
	public void ReceberVacina(Pessoa pessoa) { 
			vacina.vacinar(pessoa); 
} 
} 
```
Esta vacina tem como função ser aplicada, e o uso dela como uma <i>Interface</i> é a importante para o baixo acoplamento. 
Os diferentes tipos de vacina para COVID-19, e posteriormente de qualquer outra campanha poderão ser adicionadas e alteradas a partir da implementação da interface, este é o poder da  <b>inversão de controle</b>. A interface fica da seguinte forma: 

 ```java
package vacina.di.domain.repository; 
import vacina.di.model.Pessoa; 
public interface Vacina { 
  
	void vacinar(Pessoa pessoa); 
} 
 ```

Agora resta a adição das diferentes formas de vacina, estas classes irão implementar a classe Vacina e realizar <b>override</b> sobre o método *vacinar*, inserindo seu funcionamento distinto. Temos aqui dois exemplos na classe VacinaPfizer e VacinaAstraZeneca: 

 ```java
package vacina.di.infrastructure.repository.vacinas; 
import vacina.di.domain.repository.Vacina; 
import vacina.di.model.Pessoa; 
 
public class VacinaPfizer implements Vacina { 
	@Override 
	public void vacinar(Pessoa pessoa) { 

		System.out.printf("%s tem %d anos e recebeu a primeira dose da vacina, aguarde 15 dias para a segunda dose!\n",  
		pessoa.getNome(), 
		pessoa.getIdade()); 
 
		System.out.println("Seu sistema imunológico recebeu uma versão inativa do vírus"); 
} 
} 
 ```
 
 ```java
package vacina.di.infrastructure.repository.vacinas; 
import vacina.di.domain.repository.Vacina; 
import vacina.di.model.Pessoa; 
  
public class VacinaAstraZeneca implements Vacina { 
 
	@Override 
	public void vacinar(Pessoa pessoa) { 
		System.out.printf("%s tem %d anos e recebeu a primeira dose da vacina, aguarde 15 dias para a segunda dose!\n",  
		pessoa.getNome(), 
		pessoa.getIdade()); 
		System.out.println("Seu sistema imunológico recebeu uma versão enfraquecida do vírus"); 
} 
 
} 
 ```
 

Agora com toda a lógica implementada, podemos finalmente visualizar como fica o resultado final da nossa utilização da injeção de dependências na vacinação das personagens. É evidente a simplificação da instância, apenas construindo outro objeto já é feita toda execução do processo, <b>sem alterar uma linha interna de código sequer</b>. A classe <i>main</i> fica da seguinte forma: 

 ```java
package vacina.di; 
import vacina.di.domain.repository.Vacina; 
import vacina.di.infrastructure.repository.vacinas.VacinaAstraZeneca; 
import vacina.di.infrastructure.repository.vacinas.VacinaPfizer; 
import vacina.di.model.Pessoa; 
  
public class Main { 
  
	public static void main(String[] args) { 
 
		SpringApplication.run(VacinaApiApplication.class, args);
		Vacina vacina1 = new VacinaAstraZeneca();
		VacinaService vacinaService1 = new VacinaService(vacina1);
		Pessoa p1 = new Pessoa ("Antônio", 67);
		vacinaService1.ReceberVacina(p1);

		System.out.println("-----");
		
		Vacina vacina2 = new VacinaPfizer();
		VacinaService vacinaService2 = new VacinaService(vacina2);
		Pessoa p2 = new Pessoa ("Maria", 80);
		vacinaService2.ReceberVacina(p2);
} 

  ```
E por fim a saída será. 

 
 ```
Antônio tem 67 anos e recebeu a primeira dose da vacina, aguarde 15 dias para a segunda dose! 
Seu sistema imunológico recebeu uma versão enfraquecida do vírus 
----- 
Maria tem 80 anos e recebeu a primeira dose da vacina, aguarde 15 dias para a segunda dose! 
Seu sistema imunológico recebeu uma versão inativa do vírus 
 ```
------

##Spring Boot IOC Container e sua competência 


Para darmos continuidade ao projeto, primordialmente precisamos conhecer o <b>Spring IOC Container</b>. Ele é responsável pelos objetos gerenciados <i>Spring</i>, chamados de <b>Beans</b>. É um dos <i>pontos fortes do Spring<i>, visto que ele instancia, gerencia por  uso e faz a  injeção de dependência dos objetos de <b>forma automática</b>. Vamos ver como isso é feito na prática.


##Usando o gerenciamento Spring
O Spring é uma ferramenta bem inteligente, mas ela ainda precisa de nós para indicarmos para ela o que gerenciar. E isto é feito de forma bem prática, usando anotações, veja só:

Utilizar a anotação **@Component** é uma forma de indicarmos que nossa classe é um *Bean*. Você já deve saber que antes de utilizar um objeto você precisa referencia-lo na memoria. No exemplo temos que a classe _VacinaService_ tem como parâmetro uma Vacina, que será implementada da Interface Vacina. O Spring <i>identifica a dependência de injeção e já efetua de forma automática em <b>tempo de execução</b></i>. 

Agora utilizando uma aplicação Spring, a classe main é alterado para inicializar a aplicação Spring, com uso de *SpringApplication.run*, <i>esta questão de inicialização deve abordada em um artigo futuro com a profundidade apropriada</i>. 
Para identificar a classe é necessário a anotação **@SpringBootApplication**. 

Um boa forma de precaver erros é a utilização da anotação **@ComponentScan**, com nome autoexplicativo, é responsável por escanear a aplicação em busca dos Beans para gerenciar, para isso é necessário informar o package base onde encontra-se a aplicação. Portanto, a classe Application básica, vai se parece com algo assim:

```java
package com.gomes.daniel.vacina;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.gomes.daniel")
public class VacinaApi2Application {

	public static void main(String[] args) {
		SpringApplication.run(VacinaApiApplication.class, args);
	}

}

```


##Pontos de Injeção

Primeiramente, pontos de injeção são os locais na aplicação onde o Spring coloca as dependências de um **Bean**, por exemplo, a instanciação na construção do objeto. 
Se tivermos utilizando de polimorfismo e um objeto tiver mais de um construtor, sendo nenhum deles um construtor sem parâmetros, como o Spring sabe qual ele deve utilizar?

Neste caso que entra mais uma anotação o **@Autowired**, ela indica ao Spring, onde fazer a injeção dentro do Bean. Imagine que a nossa classe VacinaService tenha mais de um construtor, sem a anotação, o Spring iria apresentar um erro de execução ao executar o código abaixo:

```java

package com.gomes.daniel.di.infrastructure.repository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.gomes.daniel.di.domain.repository.Vacina;
import com.gomes.daniel.di.model.Pessoa;

@Component
public class VacinaService {
	
	private Vacina vacina;
	
	@Autowired
	public VacinaService(Vacina vacina) {
		this.vacina = vacina;
		System.out.println("Teste VacinaService");
	}
	
	public VacinaService(int quantidade) {
		//Alguma inicialização
	}
	
	public VacinaService(String[] locais) {
		//Alguma inicialização
	}


	public void ReceberVacina(Pessoa pessoa) {
		vacina.vacinar(pessoa);
	}
}


```

##Ambiguidade de Beans

Ambiguidade de Bean é algo muito comum em aplicações, visto que são consequencia da <b>inversão de controle</b>, como o Spring faz as injeções de maneira automática, é necessário que ele precise de uma indicação de qual Bean utilizar em casos de ambiguidade. Este problema ocorre em casos como o do projeto da Vacina, onde nosso *VacinaService* recebe um objeto Vacina, e temos VacinaPfizer e *VacinaAstraZeneca*, o que ocorre? Isso mesmo, erro na inicialização. Aí que entra nossa ultima anotação básica deste artigo a **@Primary**, responsável por indicar ao Spring qual seu Bean responsável como de injeção. 
Necessário ressaltar que existem métodos com melhores práticas que este, porém isso vale um artigo próprio e detalhado sobre, neste caso simplificado temos então como ficaria a classe  *VacinaAstraZeneca* como primária.

```java
package com.gomes.daniel.di.infrastructure.repository.vacinas;

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import com.gomes.daniel.di.domain.repository.Vacina;
import com.gomes.daniel.di.model.Pessoa;

@Primary
@Component
public class VacinaAstraZeneca implements Vacina {
	
	
	public void vacinar(Pessoa pessoa) {
		System.out.printf("%s tem %d anos e recebeu a primeira dose da vacina, aguarde 15 dias para a segunda dose!\n", 
					pessoa.getNome(),
					pessoa.getIdade());
		System.out.println("Seu sistema imunologico recebeu uma versao enfraquecida do virus");
	}
	
}
```
------
Espero que este guia rápido tenha te ajudado a ter uma leve percepção da utilização, o objetivo era elaborar um guia simples para pincelar parte uma pequena parte desta ferramenta tão vasta, este artigo faz parte do desafio Especialista Spring REST da AlgaWorks. Obrigado pela leitura. [Daniel Gomes](https://www.linkedin.com/in/danieldjgomes/)