Konstruktorabhängigkeitsinjektion im Frühjahr

1. Einleitung

Wohl eines der wichtigsten Entwicklungsprinzipien des modernen Software-Designs ist Dependency Injection (DI), das ganz natürlich aus einem anderen kritisch wichtigen Prinzip hervorgeht: der Modularität.

In diesem Artikel wird eine bestimmte Art von DI-Technik untersucht, die als konstruktorbasierte Abhängigkeitsinjektion innerhalb des Frühlings bezeichnet wird. Einfach ausgedrückt bedeutet dies, dass die erforderlichen Komponenten zum Zeitpunkt der Instanziierung an eine Klasse übergeben werden.

Um zu beginnen, müssen wir die Abhängigkeit vom Frühlingskontext in unsere pom.xml importieren :

 org.springframework spring-context 5.2.8.RELEASE 

Dann müssen wir eine Konfigurationsdatei einrichten . Diese Datei kann entweder ein POJO oder, wenn Sie es vorziehen, eine XML-Datei sein.

2. Annotationsbasierte Konfiguration

Die Java-Konfigurationsdatei ähnelt einem einfachen alten Java-Objekt mit einigen zusätzlichen Anmerkungen:

@Configuration @ComponentScan("com.baeldung.constructordi") public class Config { @Bean public Engine engine() { return new Engine("v8", 5); } @Bean public Transmission transmission() { return new Transmission("sliding"); } } 

Hier verwenden wir Annotationen, um Spring Runtime darüber zu informieren, dass diese Klasse ein Anbieter von Bean-Definitionen ist ( @ Bean- Annotation) und dass im Paket com.baeldung.spring ein Kontextscan nach zusätzlichen Beans durchgeführt werden muss . Als nächstes definieren wir eine Autoklasse :

@Component public class Car { @Autowired public Car(Engine engine, Transmission transmission) { this.engine = engine; this.transmission = transmission; } }

Spring wird bei einem Paket-Scan auf unsere Car- Klasse stoßen und ihre Instanz durch Aufrufen des mit Annotationen versehenen Konstruktors @Autowired initialisieren .

Instanzen von Engine und Transmission werden durch Aufrufen der mit @ Bean kommentierten Methoden der Config- Klasse abgerufen . Schließlich müssen wir einen ApplicationContext mit unserer POJO-Konfiguration booten:

ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); Car car = context.getBean(Car.class);

3. Implizite Konstruktorinjektion

Ab Spring 4.3 können Klassen mit einem einzelnen Konstruktor die Annotation @Autowired weglassen . Ein schönes Stück Komfort und Entfernen der Heizplatte!

Darüber hinaus kann die konstruktorbasierte Injektion ab 4.3 auch in mit @Configuration annotierten Klassen eingesetzt werden. Und ja, wenn eine solche Klasse nur einen Konstruktor hat, kann auch die Annotation @Autowired weggelassen werden.

4. XML-basierte Konfiguration

Eine andere Möglichkeit, die Spring-Laufzeit mit konstruktorbasierter Abhängigkeitsinjektion zu konfigurieren, besteht in der Verwendung einer XML-Konfigurationsdatei:

Beachten Sie, dass Konstruktor-Argument einen Literalwert oder einen Verweis auf eine andere Bean akzeptieren kann und dass ein optionaler expliziter Index und Typ angegeben werden kann. Typ- und Indexattribute können verwendet werden, um Mehrdeutigkeiten aufzulösen (z. B. wenn ein Konstruktor mehrere Argumente desselben Typs verwendet).

Das Attribut name kann auch für den Abgleich von XML- und Java-Variablen verwendet werden. Anschließend muss Ihr Code mit aktiviertem Debug-Flag kompiliert werden.

In diesem Fall muss ein Spring-Anwendungskontext mithilfe von ClassPathXmlApplicationContext gebootet werden :

ApplicationContext context = new ClassPathXmlApplicationContext("baeldung.xml"); Car car = context.getBean(Car.class);

5. Vor- und Nachteile

Die Konstruktorinjektion hat gegenüber der Feldinjektion einige Vorteile.

Der erste Vorteil ist die Testbarkeit. Angenommen, wir werden eine Spring Bean mit Feldinjektion testen:

public class UserService { @Autowired private UserRepository userRepository; }

Während der Erstellung einer UserService- Instanz können wir den userRepository- Status nicht initialisieren . Der einzige Weg, dies zu erreichen, ist die Reflection-API, die die Kapselung vollständig unterbricht. Außerdem ist der resultierende Code im Vergleich zu einem einfachen Konstruktoraufruf weniger sicher.

Zusätzlich mit Feldeinkopplung, können wir nicht auf Klassenebene Invarianten erzwingen.Es ist also möglich, eine UserService- Instanz ohne ein ordnungsgemäß initialisiertes userRepository zu haben . Daher kann es hier und da zu zufälligen NullPointerException s kommen. Mit der Konstruktorinjektion ist es außerdem einfacher, unveränderliche Komponenten zu erstellen.

Darüber hinaus ist die Verwendung von Konstruktoren zum Erstellen von Objektinstanzen vom OOP-Standpunkt aus natürlicher.

Andererseits ist der Hauptnachteil der Konstruktorinjektion ihre Ausführlichkeit, insbesondere wenn eine Bean eine Handvoll Abhängigkeiten aufweist. Manchmal kann es ein Segen in der Verkleidung sein, da wir uns möglicherweise mehr bemühen, die Anzahl der Abhängigkeiten minimal zu halten.

6. Fazit

In diesem kurzen Tutorial wurden die Grundlagen von zwei verschiedenen Möglichkeiten zur Verwendung der konstruktorbasierten Abhängigkeitsinjektion unter Verwendung des Spring-Frameworks vorgestellt.

Die vollständige Implementierung dieses Tutorials finden Sie auf GitHub.