0Pricing
Java Academy · Aula

Injeção por construtor e dependências circulares

Prefira a injeção por construtor para facilitar os testes, detecte dependências circulares e desfaça-as com @Lazy.

Injeção por construtor e dependências circulares é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.

Três tipos de injeção

O Spring é compatível com injeção por construtor (recomendada), injeção em campo (@Autowired em um campo) e injeção por método de configuração. A injeção por construtor é preferível por facilitar os testes e a imutabilidade.

Injeção por construtor

Declare as dependências como parâmetros do construtor. O Spring as injeta automaticamente. Se houver apenas um construtor, @Autowired é opcional (Spring Boot 2.1+).

@Service
public class OrderService {
    private final OrderRepository repo;
    private final EmailService email;
    // @Autowired is optional when there is only one constructor
    public OrderService(OrderRepository repo, EmailService email) {
        this.repo  = repo;
        this.email = email;
    }
}

Por que a injeção por construtor é preferível

A injeção por construtor: (1) mantém as dependências finais — imutáveis, (2) garante que a classe esteja sempre totalmente inicializada, (3) não exige uma dependência do Spring nos testes unitários — basta chamar new OrderService(mockRepo, mockEmail).

// Unit test — no Spring context needed:
OrderRepository mockRepo  = mock(OrderRepository.class);
EmailService    mockEmail = mock(EmailService.class);
OrderService    service   = new OrderService(mockRepo, mockEmail);
// Test service logic directly

Injeção em campo (evite)

A injeção em campo com @Autowired é concisa, mas problemática: os campos não podem ser final, o componente não é totalmente inicializado após a construção e os testes unitários exigem o Spring ou os auxiliares de reflexão do Mockito.

// Avoid in production code:
@Service
public class UserService {
    @Autowired  // hidden dependency
    private UserRepository repo; // cannot be final
}

Injeção por método de configuração para dependências opcionais

Use a injeção por método de configuração para dependências opcionais que tenham um valor padrão adequado — marque o método de configuração com @Autowired(required = false).

@Service
public class NotificationService {
    private SmsSender smsSender; // optional
    @Autowired(required = false)
    public void setSmsSender(SmsSender s) { this.smsSender = s; }
}

O que é uma dependência circular

Uma dependência circular ocorre quando A exige B e B exige A (direta ou transitivamente). O Spring detecta isso na inicialização e lança BeanCurrentlyInCreationException.

// CIRCULAR:
@Service class A { A(B b) {} }
@Service class B { B(A a) {} }
// Spring throws: BeanCurrentlyInCreationException: Is there an unresolvable circular reference?

Quebrando a circularidade: refatore para um terceiro serviço

A solução mais limpa é extrair a lógica compartilhada para um terceiro serviço do qual nem A nem B dependam de forma cíclica.

// Before: A <-> B
// After: A -> C, B -> C (no cycle)
@Service class SharedLogic { ... }
@Service class A { A(SharedLogic s) {} }
@Service class B { B(SharedLogic s) {} }

Quebrando a circularidade: @Lazy

Anote um ponto de injeção com @Lazy. O Spring cria imediatamente um intermediário para B; o B real só é instanciado quando A chama um método dele pela primeira vez.

@Service
public class A {
    private final B b;
    public A(@Lazy B b) { this.b = b; } // breaks the cycle
}

Quebrando a circularidade: consulta ao ApplicationContext

Injete ApplicationContext em um componente e obtenha o outro componente sob demanda por meio de context.getBean() — mas isso reduz a facilidade de teste e a clareza.

@Service
public class A implements ApplicationContextAware {
    private ApplicationContext ctx;
    public void setApplicationContext(ApplicationContext c) { this.ctx = c; }
    public void doWork() { ctx.getBean(B.class).help(); }
}

Injeção por método de configuração para quebrar a circularidade

Os componentes injetados por método de configuração são criados primeiro (a construção é concluída), depois as dependências são definidas. Isso permite dependências circulares ao custo da mutabilidade.

@Service
public class A {
    private B b;
    @Autowired public void setB(B b) { this.b = b; } // Spring sets after construction
}

spring.main.allow-circular-references (Spring Boot 2.6+)

O Spring Boot 2.6+ proíbe dependências circulares por padrão. Habilite-as explicitamente apenas como medida temporária enquanto refatora: spring.main.allow-circular-references=true.

# application.properties (temporary workaround only):
spring.main.allow-circular-references=true

Verificação rápida

Por que a injeção por construtor é preferível à injeção em campo?

Recapitulação

Prefira a injeção por construtor: imutável, testável e explícita. Evite a injeção em campo. Use @Lazy ou extraia um serviço compartilhado para quebrar dependências circulares. O Spring Boot 2.6+ sinaliza referências circulares na inicialização — trate-as como alertas de projeto.

Perguntas Frequentes

A aula “Injeção por construtor e dependências circulares” é grátis?

Sim — o texto completo de “Injeção por construtor e dependências circulares” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.

O que vou aprender em “Injeção por construtor e dependências circulares”?

Prefira a injeção por construtor para facilitar os testes, detecte dependências circulares e desfaça-as com @Lazy. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Java Academy?

Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Injeção por construtor e dependências circulares”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Java Academy?

Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Autoconfiguração e starters do Spring Boot
  2. Propriedades da aplicação e perfis
  3. Ligação de beans: @Component, @Service, @Repository
  4. Injeção por construtor e dependências circulares
← Voltar para Java Academy