Was ist Dependency Injection?
Abhängigkeitsinjektion
Dependency Injection ist ein Entwurfsprinzip, bei dem eine Klasse die Objekte, die sie zum Arbeiten braucht, von außen übergeben bekommt, statt sie selbst zu erzeugen. Damit legt nicht mehr die Klasse fest, welche konkrete Implementierung sie benutzt, sondern die Stelle, die sie zusammenbaut.
Sobald du einen Mailversand testen willst, ohne echte Mails zu verschicken, merkst du, ob die Klasse ihre Abhängigkeiten selbst erzeugt oder übergeben bekommt.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
- Gehört zu
- Inversion of Control
- Übliche Form
- Übergabe über den Konstruktor
- Container in
- Spring, .NET, Angular, NestJS
- Nutzen
- Tests mit Attrappen statt echter Systeme
Der Unterschied an einem Beispiel
Eine Klasse zur Rechnungsstellung, die in ihrem Konstruktor selbst einen konkreten Mailversand erzeugt, ist an genau diesen Versand gebunden. Wer sie testet, verschickt Mails. Wer sie in einer anderen Umgebung nutzen will, muss den Quelltext ändern.
Übergibst du stattdessen ein Objekt, das eine Versandschnittstelle erfüllt, entscheidet der Aufrufer. In der Produktion reicht er den echten Versand herein, im Test eine Attrappe, im Englischen Mock oder Fake, die den Aufruf nur aufzeichnet. In Java sieht das so aus:
// Without DI: the class creates its own dependency
class RechnungService {
private final MailVersand versand = new SmtpMailVersand();
}
// With constructor injection: the caller decides
class RechnungService {
private final MailVersand versand;
RechnungService(MailVersand versand) {
this.versand = versand;
}
}
// Production and test use the same class
new RechnungService(new SmtpMailVersand());
new RechnungService(new FakeMailVersand()); Das ist der ganze Kern. Alles Weitere, Container, Annotationen, Konfigurationsdateien, ist Bequemlichkeit für den Fall, dass es nicht um zwei, sondern um zweihundert Objekte geht. Den Namen Dependency Injection hat Martin Fowler 2004 in einem Artikel geprägt, der die damals neuen Container für Java verglich.
Constructor, Setter und Field Injection
Bei der Constructor Injection kommen alle Abhängigkeiten über den Konstruktor herein. Das ist die empfohlene Form, weil ein Objekt danach vollständig ist und Felder final sein können. Bleibt eine Abhängigkeit optional, bietet sich Setter Injection an. Von der Field Injection, also der Zuweisung direkt an die Felder, raten die meisten Teams ab, weil sich das Objekt außerhalb des Frameworks nicht mehr ohne Reflexion aufbauen lässt und die Liste der Abhängigkeiten unsichtbar wird.
Was ein DI-Container macht
Ein Container übernimmt das Zusammenstecken. Du registrierst, welche Implementierung für welche Schnittstelle gelten soll, und der Container erzeugt die Objekte, erkennt am Konstruktor, was gebraucht wird, und liefert passende Instanzen. Er verwaltet außerdem die Lebensdauer, also ob ein Objekt einmal pro Anwendung, einmal pro Anfrage oder bei jedem Bedarf neu existiert.
In Java ist Spring der verbreitetste Container, Jakarta EE macht dasselbe über CDI mit der Annotation @Inject. In .NET ist ein Container fest eingebaut, dort heißen die drei Lebensdauern Singleton, Scoped und Transient. Angular und NestJS bringen ebenfalls eigene DI-Systeme mit, in denen Services über den Konstruktor oder die Funktion inject() angefordert werden.
Wo es kippt
Der typische Stolperstein sind Zyklen. Wenn A B braucht und B wiederum A, kommt der Container beim Aufbau nicht weiter. Hier hilft kein Trick, sondern die Frage, welche gemeinsame Aufgabe in eine dritte Klasse gehört.
Nicht jede Abhängigkeit muss injiziert werden. Eine Klasse für ein Datum oder eine Liste erzeugst du weiterhin direkt. Das Prinzip zielt auf alles, was du in einem Test austauschen oder in einer anderen Umgebung anders verdrahten willst, typischerweise Datenbankzugriffe, externe Dienste, Uhrzeit und Konfiguration.
Dependency Injection und was oft damit gleichgesetzt wird
Inversion of Control ist das übergeordnete Prinzip, dass nicht dein Code den Ablauf steuert, sondern ein Rahmenwerk, das deinen Code aufruft. Dependency Injection ist eine konkrete Ausprägung davon, bezogen auf das Beschaffen von Abhängigkeiten.
Das „D“ in SOLID besagt, dass Klassen von Abstraktionen abhängen sollen, nicht von konkreten Implementierungen. Das ist eine Entwurfsregel. Dependency Injection ist die Technik, mit der die konkrete Implementierung dann von außen hereinkommt.
Beim Service Locator holt sich die Klasse ihre Abhängigkeiten aktiv aus einem Verzeichnis. Sie kennt dieses Verzeichnis dann und ist damit schwerer isoliert zu testen als eine Klasse, die alles übergeben bekommt.
Eine Factory kapselt die Erzeugung von Objekten. Sie kann Teil der Lösung sein, nimmt der Klasse aber nicht die Entscheidung ab, welche Implementierung sie benutzt.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Der Konstruktor verrät, wie es um die Klasse steht
Wenn eine Klasse acht Dinge übergeben bekommt, ist nicht die Injektion das Problem, sondern der Zuschnitt. Der Konstruktor listet ungeschönt auf, wovon die Klasse abhängt, und diese Liste ist der beste Hinweis darauf, dass hier zwei oder drei Aufgaben in einer Datei liegen.
Mit einem Container fällt ein Teil der Fehler erst beim Start der Anwendung auf statt beim Übersetzen. Fehlt eine Registrierung, merkst du davon im Editor nichts, sondern erst, wenn der Dienst hochfährt. Deshalb gehört ein Test dazu, der den Container einmal vollständig aufbaut.
Am unangenehmsten sind falsche Lebensdauern. Ein Objekt, das nur einmal existiert und sich dabei etwas aus dem aktuellen Aufruf merkt, gibt diese Information beim nächsten Aufruf an jemand anderen weiter. Solche Fehler treten unter Last auf und lassen sich am Arbeitsplatz kaum nachstellen.
Dependency Injection lernen
Wie der Container Objekte findet, verdrahtet und verwaltet, machen die Trainings zum Spring-Framework an einer Anwendung nachvollziehbar, die du selbst aufbaust.
Kurse, die Dependency Injection behandeln
Häufige Fragen
Wie heißt Dependency Injection auf Deutsch?
Brauche ich für Dependency Injection ein Framework?
Warum Constructor statt Field Injection?
Was tun bei mehreren passenden Implementierungen?
Passt thematisch dazu
Der größte Gewinn liegt in schnellen Tests mit Attrappen, und wo deren Grenze verläuft, klärt die Frage, wie viele Unit-Tests neben Integrationstests sinnvoll sind.
Deine Ansprechpartner
Du willst das Thema nicht nur nachschlagen, sondern anwenden können? Wir beraten dich persönlich und kostenlos.
Yves Hoppe
Weiterbildung & Beratung
Ordnet mit dir ein, welcher Kurs zu deinem Vorwissen passt.
Norbert Jansen
Beratung & Inhouse
Plant Inhouse-Trainings, die an euren eigenen Daten und Abläufen ansetzen.
Dependency Injection im Kurs statt im Lexikon
Nachschlagen bringt dich bis zum Verstehen. Anwenden lernst du an echten Aufgaben.