Injeção de Dependências (Dependency Injection) em Java: guia completo

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que Dependency Injection é indispensável para o desenvolvedor Java

Todo desenvolvedor Java, mais cedo ou mais tarde, enfrenta o problema do forte acoplamento de código. Quando uma classe cria diretamente instâncias de outras classes, o sistema se torna frágil, difícil de testar e modificar. A solução para esse problema é o Dependency Injection (DI), ou injeção de dependências. Este é um dos princípios-chave do desenvolvimento moderno, que está na base de frameworks como Spring e Jakarta EE.

Neste artigo, vamos analisar o que é DI, como ele difere de IoC (Inversion of Control), explorar as três principais formas de injeção de dependências em Java com exemplos de código práticos, e discutir por que esse padrão é necessário para criar aplicações sustentáveis.



O que é Dependency Injection e Inversion of Control?

Antes de passarmos ao código, é importante entender dois conceitos fundamentais.

Inversion of Control (IoC) é um princípio geral no qual o fluxo de controle do programa é transferido para um framework ou contêiner externo. Em vez de o próprio código decidir quando criar objetos e chamar métodos, isso é feito por um sistema externo.

Dependency Injection é uma implementação específica do princípio IoC. É um padrão no qual um objeto recebe suas dependências (outros objetos dos quais ele depende) de fora, em vez de criá-los ele mesmo.

Simplificando, em vez de a classe Car criar o motor ela mesma (new Engine()), ela recebe um motor pronto através do construtor ou setter. Isso torna a classe Car independente da implementação específica de Engine.



Três formas de injeção de dependências em Java

Em Java, existem três formas principais de implementar DI. Vamos analisar cada uma delas usando um exemplo simples de sistema de notificações.



1. Injeção via construtor (Constructor Injection)

Esta é a forma mais recomendada e segura. As dependências são passadas através do construtor da classe. Isso garante que o objeto nunca seja criado em um estado inválido, pois todas as dependências necessárias são obrigatórias.

// Interface para o serviço de notificaçõespublic interface MessageService {    void sendMessage(String message, String recipient);}

// Implementação para Emailpublic class EmailService implements MessageService { @Override public void sendMessage(String message, String recipient) { System.out.println("Email sent to " + recipient + ": " + message); }}

// Classe que usa o serviço de notificaçõespublic class NotificationSender { private final MessageService service; // Dependência

// Injeção via construtor public NotificationSender(MessageService service) { this.service = service; }

public void notifyUser(String user, String msg) { this.service.sendMessage(msg, user); }}

// Usopublic class Main { public static void main(String[] args) { MessageService emailService = new EmailService(); NotificationSender sender = new NotificationSender(emailService); // DI sender.notifyUser("user@example.com", "Hello!"); }}


2. Injeção via setter (Setter Injection)

Esta forma é usada quando a dependência não é obrigatória ou pode ser alterada após a criação do objeto. A dependência é passada através de um método setter público.

public class NotificationSenderWithSetter {    private MessageService service; // Dependência não obrigatória

// Setter para injeção public void setMessageService(MessageService service) { this.service = service; }

public void notifyUser(String user, String msg) { if (service != null) { this.service.sendMessage(msg, user); } else { System.out.println("No service configured!"); } }}

// Uso

Blogs

Book Recommendations