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 directlyInjeçã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=trueVerificaçã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
- Autoconfiguração e starters do Spring Boot
- Propriedades da aplicação e perfis
- Ligação de beans: @Component, @Service, @Repository
- Injeção por construtor e dependências circulares