Como alavancar sua carreira JAVA conhecendo a injeção de dependência do Spring.
Tags: java, tutorial
Published: 2021-02-10 14:43:46

###Estudando sobre Spring Framework e as tecnologias da ferramenta para facilitar o desenvolvimento JAVA, certamente vai se deparar com a **injeção de dependência**. Talvez, como eu, já tenha usado sem compreender muito, mas chegou a hora de desvendá-la.###


Uma das facilidades é como container spring gerencia todo o ciclo de vida das dependências do projeto. Para entender isso, irei apresentá-lo ao conceito de inversão de dependência, depois vamos ver na prática, como usar isso para facilitar e ganhar agilidade no desenvolvimento ou manutenção do projeto JAVA.

[*1 - Container Spring.*](#capitulo-1)
[*2 - Configurando dependências manualmente.*](#capitulo-2)
[*3 - Conceito de injeção de dependência.*](#capitulo-3)
[*4 - Criando Bean gerenciável pelo Spring.*](#capitulo-4)
[*5 - Injetando dependência com o construtor.*](#capitulo-5)
[*6 - Injetando dependência com o método Setter.*](#capitulo-6)
[*7 - Injetando dependência no atributo.*](#capitulo-7)


### Container Spring<a name="capitulo-1"></a>

Ao desenvolver o projeto com Spring Framework, as classes serão criadas, definimos tudo que será necessário para o seu funcionamento, o IoC Container, é o responsável por gerenciar essas dependências.
O IoC container, promove o que chamamos de inversão de dependência e usamos a Injeção de dependência 
para obter essa inversão. Normalmente, ao criar objetos JAVA, fazemos a instanciação durante o uso, com o `new Object();`. Isso pode ser bem trabalhoso e repetitivo, veja o exemplo de uma classe controladora do DAO (Data Acess Object), que tem o objetivo de carregar dados de um cliente no banco de dados.

### Configurando dependências manualmente.<a name="capitulo-2"></a>

_*Classe ClienteController*_

```
public class ClienteController {

   ClienteDAO clienteDao;
   
   public Cliente salvar(Cliente cliente) {
      clienteDao = new ClienteDAO();
      return clienteDao.add(cliente);
   }

   public List<Cliente> listarTodos() {
      clienteDao = new ClienteDAO();
      return clienteDao.list();
   }

   public Cliente alterar(Cliente cliente) {
      clienteDao = new ClienteDAO();
      return clienteDao.add(cliente);
   }

   public void excluir(Cliente cliente) {
      clienteDao = new ClienteDAO();
      clienteDao.remove(cliente);
   }

   public Cliente consultaPorId(Long id) {
      clienteDao = new ClienteDAO();
      return clienteDao.findById(id);
   }
}

```

Observe que, tenho que instanciar manualmente o meu clienteDao, a classe ClienteController passa então, a ter uma dependência, sendo então necessário um ClienteDaO para que ela funcione.
Veja outro exemplo, agora na classe ClienteDAO, onde tenho que instanciar e abrir as conexões para o banco de dados:

_*Classe ClienteDAO*_

```
public class ClienteDAO implements DataAcessObject<Cliente> {

	private PreparedStatement query = null;
	private ResultSet rs = null;

	@Override
	public List<Cliente> list() {
		Connection conn = ConnectionFactory.abrirConexao(); /* instanciando o objeto */
		String sql = "Select * from clientes where not ind_deletado";
		List<Cliente> clientes = new ArrayList<Cliente>();
		Cliente cliente = null;

		try {
			query = conn.prepareStatement(sql);
			rs = query.executeQuery();
			while (rs.next()) {
				cliente = new Cliente(rs.getString("nome"), rs.getString("telefone"), rs.getString("email"));
				clientes.add(cliente);
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} finally {
			ConnectionFactory.fecharConexao(conn, query, rs);
		}
		return clientes;

	}

	@Override
	public List<Cliente> findByName(String name) {
		Connection conn = ConnectionFactory.abrirConexao();/* instanciando o objeto */
		String sql = "Select * from clientes where not ind_deletado and nome like ? ";
		List<Cliente> clientes = new ArrayList<Cliente>();
		Cliente cliente = null;

		try {
			query = conn.prepareStatement(sql);
			query.setString(1, "%" + name + "%");
			rs = query.executeQuery();
			while (rs.next()) {
				cliente = new Cliente(rs.getString("nome"), rs.getString("email"), rs.getString("telefone"));
				clientes.add(cliente);
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} finally {
			ConnectionFactory.fecharConexao(conn, query, rs);
		}

		return clientes;
	}
/*Outros métodos da interface...*/
}

```
Da mesma forma que no objeto anterior, tenho que dizer quais são as dependências, aqui teremos que instanciar Connection, PreparedStatement, ResultSet.
Esta é a forma tradicional, onde declaramos as dependências de forma manual, em cada classe ou método, isso promove acoplamento, tornando complicada a manutenção. Um conceito de segurança de dados, é o de que, toda conexão aberta, deve ser fechada, também fazemos isso hard-code.
Na classe ClienteDaO, os métodos possuem try, catch e finally. No finally, é o momento em que a aplicação identifica que não preciso mais do objeto `Connection conn;` e ele pode ser descartado. Abrir conexões com o banco, consomem bastante processamento, o spring pode facilitar essa ação, abrindo uma conexão no inicio da aplicação, segurando ela durante todo o processo, esse é o padrão Singleton, então vamos usar o Spring para fazer essas configurações de forma mais inteligente e simplificada.

###Conceito de injeção de dependência.<a name="capitulo-3"></a>

Injeção de Dependência, D.I ou Dependency Injection, remete a ideia de algo que vem de fora para dentro, o IoC tem a obrigação de instanciar, configurar e montar as dependências da nossa classe. Bean é como todo e qualquer objeto que será gerenciado pelo IoC Container é chamado. Classes de domínio, como a classe Cliente, não devem ser Beans, pois não quero criar vários objetos do tipo Cliente quando a aplicação é iniciada, faremos isso manualmente onde for necessário, é a forma correta, usamos injeção de dependência normalmente em classes de serviço ou DAO.

_*Como o Spring Funciona:*_
![Como o spring funciona](https://dev-to-uploads.s3.amazonaws.com/i/qyup90vnxyq3ig99lc2o.JPG)

###Criando Bean gerenciável pelo Spring.<a name="capitulo-4">

Agora que sabemos o conceito de injeção de dependência, e como ela funciona, vamos ver como facilitar isso usando a ferramenta.
Temos alguns pontos de Injeção no Spring framework, podemos configurá-la em arquivos xml, mas vamos fazer por meio das anotações, não porque são melhores que o xml, mas pelo contexto que é a busca por praticidade.
Notações são palavras reservadas do framework, metadados que usamos para marcar métodos, classes ou declaração, atributo. O IoC Container, só consegue gerenciar componentes Spring, por esse motivo marcamos as classes com _@Component_ ou ainda com _@Controller_, _@Repository_, _@Service_, todos eles são _@Component_ e podem ser gerenciados pelo spring.
Então vamos marcar a classe ClienteDAO com _@Repository_ e vamos fazer um construtor na classe ClienteController, ele será o nosso primeiro ponto de injeção.


_*Classe ClienteDAO agora com @Repository*_

```
@Repository
public class ClienteDAO implements DataAcessObject<Cliente> {

	private PreparedStatement query = null;
	private ResultSet rs = null;
	
	public ClienteDAO() {
		System.out.println("EU CHAMEI O CLIENTE DAO AO INICIAR");
	}

	@Override
	public List<Cliente> list() {
		Connection conn = ConnectionFactory.abrirConexao(); /* instanciando o objeto */
		String sql = "Select * from clientes where not ind_deletado";
		List<Cliente> clientes = new ArrayList<Cliente>();
		Cliente c = null;

		try {
			query = conn.prepareStatement(sql);
			rs = query.executeQuery();
			while (rs.next()) {
				c = new Cliente(rs.getString("nome"), rs.getString("telefone"), rs.getString("email"));
				clientes.add(c);
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} finally {
			ConnectionFactory.fecharConexao(conn, query, rs);
		}
		return clientes;

	}

	@Override
	public List<Cliente> findByName(String name) {
		Connection conn = ConnectionFactory.abrirConexao();/* instanciando o objeto */
		String sql = "Select * from clientes where not ind_deletado and nome like ? ";
		List<Cliente> clientes = new ArrayList<Cliente>();
		Cliente c = null;

		try {
			query = conn.prepareStatement(sql);
			query.setString(1, "%" + name + "%");
			rs = query.executeQuery();
			while (rs.next()) {
				c = new Cliente(rs.getString("nome"), rs.getString("email"), rs.getString("telefone"));
				clientes.add(c);
			}
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} finally {
			ConnectionFactory.fecharConexao(conn, query, rs);
		}

		return clientes;
	}

/*Outros métodos da classe*/
```

###Injetando dependência através do construtor.<a name="capitulo-5">

Ajustamos a classe ClienteDAO para que ela seja um component Spring e possa ser encontrada no start da aplicação por meio da marcação _@Repository_, agora faremos a injeção de dependência por meio do construtor na Classe ClienteController.
Desse modo, o contêiner do Spring, ao iniciar a aplicação, verifica que existe a necessidade de inserir na classe ClienteController alguma instância de objeto, no momento que a aplicação inicia, é feita a criação e os métodos de clienteDao já podem ser usados pela classe.

_Classe ClienteController com anotação @Controller_
```
@Controller
public class ClienteController {
	ClienteDAO clienteDao;

	public ClienteController(ClienteDAO clienteDao) {
		this.clienteDao = clienteDao;
	}
	public Cliente salvar(Cliente cliente) {
		return clienteDao.add(cliente);
	}
	public List<Cliente> listarTodos() {
		return clienteDao.list();
	}
	public Cliente alterar(Cliente cliente) {
		return clienteDao.add(cliente);
	}
	public void excluir(Cliente cliente) {
		clienteDao.remove(cliente);
	}
	public Cliente consultaPorId(Long id) {
		return clienteDao.findById(id);
	}
}

```

###Injetando dependência com o método Setter<a name="capitulo-6"></a>

Podemos usar um método Setter para fazer a injeção de dependência, a classe ClienteDAO, permanece da mesma forma, iremos alterar a classe ClienteController, não sendo mais necessário o construtor. Usamos um método Setter para configurar o atributo ClienteDAO.

@Autowired é uma anotação que usamos para fazer a configuração do método setter, é ela que o container spring vai procurar para fazer a injeção.

_*Classe ClienteController com injeção no método Setter*_
```
@Controller
public class ClienteController {
	private ClienteDAO clienteDao;

	@Autowired
	public void setClienteDao(ClienteDAO clienteDao) {
		this.clienteDao = clienteDao;
	}
	
	public Cliente salvar(Cliente cliente) {
		return clienteDao.add(cliente);
	}
	public List<Cliente> listarTodos() {
		return clienteDao.list();
	}
	public Cliente alterar(Cliente cliente) {
		return clienteDao.add(cliente);
	}
	public void excluir(Cliente cliente) {
		clienteDao.remove(cliente);
	}
	@GetMapping("findId")
	@ResponseBody
	public Cliente consultaPorId(Long id) {
		return clienteDao.findById(id);
	}
}

```
###Injetando dependência no atributo.<a name="capitulo-7"></a>

Nas configurações anteriores, alteramos o construtor e fizemos um método setter, isso já facilita o desenvolvimento e torna o código menos acoplado, mas podemos fazer de forma mais simples, veja:

_*Classe ClienteController com injeção no atributo*_
```
@Controller
public class ClienteController {
	@Autowired
	private ClienteDAO clienteDao;
	
	public Cliente salvar(Cliente cliente) {
		return clienteDao.add(cliente);
	}
	public List<Cliente> listarTodos() {
		return clienteDao.list();
	}
	public Cliente alterar(Cliente cliente) {
		return clienteDao.add(cliente);
	}
	public void excluir(Cliente cliente) {
		clienteDao.remove(cliente);
	}
	@GetMapping("findId")
	@ResponseBody
	public Cliente consultaPorId(Long id) {
		return clienteDao.findById(id);
	}
}

```

Simplesmente colocando a anotação, vou poder acessar e usar os métodos do clienteDao sem nenhum problema, isso ocorre porque o IoC container inverte a ordem como as dependências são inseridas, pegando para si essa responsabilidade. Cada desenvolvedor tem seus hábitos e práticas, alguns preferem usar xml para deixar as classes mais limpas, outros usam o construtor, mas certamente a mais utilizada por mim é no atributo.

Você já conhecia o conceito de injeção de dependência e inversão de controller, consegui te ajudar? Deixe seu comentário.

*Artigo escrito para o desafio do curso Especialista Spring Rest da AlgaWorks*


_Referências:_
_[Documentação Spring](https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/beans.html)_
_[AlgaWorks - Injeção de dependência com Spring](https://blog.algaworks.com/injecao-de-dependencias-com-spring/)_
_[DevMedia - Injeção de dependência JAVA JSR-330](https://www.devmedia.com.br/injecao-de-dependencias-em-java-com-jsr-330-e-spring/27948)_
_[Tutorials Point - Dependency Injection](https://www.tutorialspoint.com/spring/spring_dependency_injection.htm)_