0
respostas

Criei um sistema Java de Injeção de dependência (DI)

Injeção de Dependência Simples em Java

O JToolbox Dependency Injector (DI) é um container leve de Inversao de Controle (IoC) desenvolvido para simplificar o gerenciamento de componentes (services) e suas dependências em aplicações Java.

Vantagens Principais do Uso

O objetivo do DI é transferir a responsabilidade de criar e conectar objetos do seu código para o container.

  1. Redução de Acoplamento (Loose Coupling): Seus objetos consomem dependências através de interfaces ou construtores, sem usar o operador new. Isso permite que você mude a implementação de um serviço (ex: Correios para PatrusTransportes) sem alterar o código que o consome (Freight).

  2. Testabilidade: A injeção por construtor ou por campo permite que você substitua facilmente as dependências reais por objetos Mock durante testes unitários, isolando o componente em teste.

  3. Gerenciamento de Ciclo de Vida: O DI gerencia quando e como um objeto é criado, garantindo a criação única (SINGLETON) ou a criação sob demanda (PROTOTYPE).

Anotações Chave e Seus Usos

O sistema é baseado em quatro anotações simples que definem o comportamento dos componentes.

1. @Service (Definição do Componente)
Marca uma classe para ser gerenciada pelo container DI.

ParâmetroDescriçãoExemplo
value (String)Nome único para qualificar o serviço (usado pelo @Qualifier).@Service(value = "prod")
scope (ScopeType)Define o ciclo de vida da instância.@Service(scope = ScopeType.PROTOTYPE)

Exemplo de Scope:

  • SINGLETON (Padrão): O objeto é criado uma única vez e reutilizado em todas as injeções. Ideal para serviços sem estado (stateless) como Loggers, Factories e Calculators.

  • PROTOTYPE: Uma nova instância é criada toda vez que é injetada ou solicitada. Ideal para objetos com estado específico que precisam ser isolados (ex: uma transação de banco de dados ou um Tarefa com estado).

2. @Qualifier (Resolução de Ambiguidade)
Usado para especificar qual implementação de uma interface deve ser injetada quando houver mais de uma. O value deve corresponder ao value da anotação @Service da implementação desejada.

@Service
public class Freight {

    private final FreightInterface freightInterface;

    // Injeta a implementação anotada com @Service(value = "correios")
    public Freight(@Qualifier("correios") FreightInterface freightInterface) {
        this.freightInterface = freightInterface;
    }

3. @Inject (Injeção por Campo)
Marca um campo para que o container injete o serviço correspondente após a criação do objeto (depois da execução do construtor).

public class MyService {
    @Inject
    private Logger logger; // O logger será injetado após a construção.
}

4. @PostConstruct (Hook de Inicialização)
Marca um método (que deve ser parameterless) para ser executado depois que o objeto foi construído e todas as suas dependências (@Inject e construtor) foram resolvidas.

@Service
public class DatabaseConnector {
    // construtor injeta a Configuração
    
    @PostConstruct
    public void initializeConnection() {
        // Abrir a conexão, pois todas as dependências estão prontas.
    }
}

Outro exemplo simples:

Object Task

package com.github.rickmvi.app.task;

import com.github.rickmvi.jtoolbox.container.ScopeType;
import com.github.rickmvi.jtoolbox.container.annotations.Service;
import lombok.Setter;

import static com.github.rickmvi.jtoolbox.console.IO.*;

@Service(value = "task", scope = ScopeType.PROTOTYPE)
public class Task {

    @Setter
    private String description;

    @Setter
    private boolean conclude;

    public void display() {
        if (!conclude) {
            format("Task: {0} - Status: Pending$n", description);
            return;
        }
        format("Task: {0} - Status: Completed$n", description);
    }
}

Class Main

package com.github.rickmvi.app;

import com.github.rickmvi.app.task.Task;
import com.github.rickmvi.jtoolbox.collections.Dynamic;
import com.github.rickmvi.jtoolbox.container.Dependency;

public class Main {
    public static void main(String[] args) {
        Dependency injector = Dependency.inject("com.github.rickmvi.app.task").get();
        
        Task t1 = injector.get(Task.class);
        t1.setDescription("To study Java");
        t1.setConclude(false);

        Task t2 = injector.get(Task.class);
        t2.setDescription("Do exercises");
        t2.setConclude(true);

        Dynamic<Task> list = Dynamic.of(t1, t2);

        list.forEachDo(Task::display);
    }
}

image

Matricule-se agora e aproveite até 50% OFF

O maior desconto do ano para você evoluir com a maior escola de tecnologia

QUERO APROVEITAR