Konstruktor-Injektion und zirkuläre Abhängigkeiten
Bevorzugen Sie für bessere Testbarkeit die Konstruktor-Injektion, erkennen Sie zirkuläre Abhängigkeiten und lösen Sie sie mit @Lazy auf.
Konstruktor-Injektion und zirkuläre Abhängigkeiten ist eine kostenlose Java Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Java Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.
Drei Injection-Arten
Spring unterstützt Constructor Injection (empfohlen), Field Injection (@Autowired an einem Feld) und Setter Injection. Constructor Injection wird wegen der besseren Testbarkeit und Unveränderlichkeit bevorzugt.
Constructor Injection
Definieren Sie Abhängigkeiten als Konstruktorparameter. Spring injiziert sie automatisch. Gibt es nur einen Konstruktor, ist @Autowired optional (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;
}
}Warum Constructor Injection bevorzugt wird
Constructor Injection: (1) Abhängigkeiten sind final – unveränderlich, (2) die Klasse ist immer vollständig initialisiert, (3) Unit-Tests benötigen keine Spring-Abhängigkeit – rufen Sie einfach new OrderService(mockRepo, mockEmail) auf.
// 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 directlyField Injection (vermeiden)
Field Injection mit @Autowired ist zwar kompakt, aber problematisch: Felder können nicht final sein, die Bean ist nach der Erstellung nicht vollständig initialisiert, und für Unit-Tests werden Spring oder die Reflection-Hilfsmethoden von Mockito benötigt.
// Avoid in production code:
@Service
public class UserService {
@Autowired // hidden dependency
private UserRepository repo; // cannot be final
}Setter Injection für optionale Abhängigkeiten
Verwenden Sie Setter Injection für optionale Abhängigkeiten mit einem sinnvollen Standardwert – annotieren Sie den Setter mit @Autowired(required = false).
@Service
public class NotificationService {
private SmsSender smsSender; // optional
@Autowired(required = false)
public void setSmsSender(SmsSender s) { this.smsSender = s; }
}Was ist eine zyklische Abhängigkeit?
Eine zyklische Abhängigkeit tritt auf, wenn A B benötigt und B A benötigt (direkt oder transitiv). Spring erkennt dies beim Start und wirft BeanCurrentlyInCreationException.
// CIRCULAR:
@Service class A { A(B b) {} }
@Service class B { B(A a) {} }
// Spring throws: BeanCurrentlyInCreationException: Is there an unresolvable circular reference?Zyklische Abhängigkeiten auflösen: In dritten Service auslagern
Die sauberste Lösung besteht darin, die gemeinsame Logik in einen dritten Service auszulagern, von dem weder A noch B zyklisch abhängt.
// 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) {} }Zyklische Abhängigkeiten auflösen: @Lazy
Annotieren Sie einen Injection Point mit @Lazy. Spring erstellt zunächst einen Proxy für B; die tatsächliche Instanz von B wird erst erzeugt, wenn A erstmals eine Methode darauf aufruft.
@Service
public class A {
private final B b;
public A(@Lazy B b) { this.b = b; } // breaks the cycle
}Zyklische Abhängigkeiten auflösen: ApplicationContext-Lookup
Injizieren Sie ApplicationContext in eine Bean und suchen Sie die andere Bean bei Bedarf über context.getBean() – dadurch werden jedoch Testbarkeit und Verständlichkeit beeinträchtigt.
@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(); }
}Setter Injection zum Auflösen zyklischer Abhängigkeiten
Per Setter injizierte Beans werden zuerst erstellt (die Konstruktion gelingt), anschließend werden die Abhängigkeiten gesetzt. Dadurch werden zyklische Abhängigkeiten ermöglicht, allerdings auf Kosten der Veränderlichkeit.
@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+)
Spring Boot 2.6+ verbietet zyklische Abhängigkeiten standardmäßig. Aktivieren Sie sie nur vorübergehend während einer Umstrukturierung: spring.main.allow-circular-references=true.
# application.properties (temporary workaround only):
spring.main.allow-circular-references=trueSchnelltest
Warum wird Constructor Injection gegenüber Field Injection bevorzugt?
Zusammenfassung
Bevorzugen Sie Constructor Injection: unveränderlich, testbar und explizit. Vermeiden Sie Field Injection. Verwenden Sie @Lazy oder lagern Sie eine gemeinsame Funktionalität in einen eigenen Service aus, um zyklische Abhängigkeiten aufzulösen. Spring Boot 2.6+ meldet zyklische Referenzen beim Start – betrachten Sie sie als Warnzeichen für das Design.
Häufig gestellte Fragen
Ist die Lektion „Konstruktor-Injektion und zirkuläre Abhängigkeiten“ kostenlos?
Ja — der vollständige Text von „Konstruktor-Injektion und zirkuläre Abhängigkeiten“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Java Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Konstruktor-Injektion und zirkuläre Abhängigkeiten“?
Bevorzugen Sie für bessere Testbarkeit die Konstruktor-Injektion, erkennen Sie zirkuläre Abhängigkeiten und lösen Sie sie mit @Lazy auf. Du übst Java Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Java Academy zu starten?
Keine Vorkenntnisse erforderlich. Java Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Konstruktor-Injektion und zirkuläre Abhängigkeiten“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Java Academy-Lektion Code schreiben und ausführen?
Ja. Jede Java Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Automatische Konfiguration und Spring-Boot-Starter
- Anwendungseigenschaften und Profile
- Bean-Verdrahtung: @Component, @Service, @Repository
- Konstruktor-Injektion und zirkuläre Abhängigkeiten