Java Dependency Injection design pattern ermöglicht es uns, entfernen Sie die fest codierte Abhängigkeiten und machen unsere Anwendung lose gekoppelt, erweiterbar und wartbar. Wir können Dependency Injection in Java implementieren, um die Abhängigkeitsauflösung von der Kompilierungszeit zur Laufzeit zu verschieben.,
Java Dependency Injection
Java Dependency Injection scheint mit der Theorie schwer zu verstehen, also würde ich ein einfaches Beispiel nehmen und dann werden wir sehen, wie man Abhängigkeitsinjektionsmuster verwendet, um lose Kopplung und Erweiterbarkeit in der Anwendung zu erreichen.
Angenommen, wir haben eine Anwendung, in der wir EmailService
zum Senden von E-Mails verwenden. Normalerweise würden wir dies wie folgt implementieren.
EmailService
Die Klasse enthält die Logik zum Senden einer E-Mail-Nachricht an die E-Mail-Adresse des Empfängers., Unser Anwendungscode wird wie unten sein.
Unser Client-Code, der die MyApplication
– Klasse zum Senden von E-Mail-Nachrichten verwendet, ist wie folgt.
Auf den ersten Blick scheint an der obigen Implementierung nichts auszusetzen. Die obige Codelogik hat jedoch bestimmte Einschränkungen.
-
MyApplication
Die Klasse ist dafür verantwortlich, den E-Mail-Dienst zu initialisieren und dann zu verwenden. Dies führt zu einer fest codierten Abhängigkeit. Wenn wir in Zukunft zu einem anderen erweiterten E-Mail-Dienst wechseln möchten, sind Codeänderungen in der MyApplication Klasse erforderlich., Dies macht unsere Anwendung schwer zu erweitern und wenn der E-Mail-Dienst in mehreren Klassen verwendet wird, wäre dies noch schwieriger. - Wenn wir unsere Anwendung erweitern möchten, um eine zusätzliche Messaging-Funktion wie SMS oder Facebook-Nachricht bereitzustellen, müssen wir dafür eine andere Anwendung schreiben. Dies beinhaltet Codeänderungen in Anwendungsklassen und auch in Clientklassen.
- Das Testen der Anwendung wird sehr schwierig sein, da unsere Anwendung die E-Mail-Dienstinstanz direkt erstellt. Es gibt keine Möglichkeit, diese Objekte in unseren Testklassen zu verspotten.,
Man kann argumentieren, dass wir die E-Mail-Dienstinstanzerstellung aus der MyApplication
– Klasse entfernen können, indem wir einen Konstruktor haben, der E-Mail-Dienst als Argument benötigt.
In diesem Fall bitten wir jedoch Clientanwendungen oder Testklassen, den E-Mail-Dienst zu initialisieren, was keine gute Designentscheidung ist.
Nun wollen wir sehen, wie wir Java Dependency Injection Pattern anwenden können, um alle Probleme mit der obigen Implementierung zu lösen., Abhängigkeitsinjektion in Java erfordert mindestens Folgendes:
- Servicekomponenten sollten mit Basisklasse oder Schnittstelle entworfen werden. Es ist besser, Schnittstellen oder abstrakte Klassen zu bevorzugen, die den Vertrag für die Dienste definieren.
- Consumer-Klassen sollten in Bezug auf die Serviceschnittstelle geschrieben werden.
- Injektorklassen, die die Dienste und dann die Consumer-Klassen initialisieren.
Java Dependency Injection-Service Components
In unserem Fall können wir MessageService
, die den Vertrag für Service-Implementierungen deklarieren.,
package com.journaldev.java.dependencyinjection.service;public interface MessageService {void sendMessage(String msg, String rec);}
Angenommen, wir haben E-Mail – und SMS-Dienste, die die oben genannten Schnittstellen implementieren.
Unsere Java-Dienste zur Abhängigkeitsinjektion sind bereit und jetzt können wir unsere Consumer-Klasse schreiben.
Java Dependency Injection-Service Consumer
Wir müssen keine Basisschnittstellen für Consumer-Klassen haben, aber ich werde eine Consumer
Schnittstelle haben, die den Vertrag für Consumer-Klassen deklariert.
package com.journaldev.java.dependencyinjection.consumer;public interface Consumer {void processMessages(String msg, String rec);}
Meine Implementierung der Consumer-Klasse ist wie folgt.
Beachten Sie, dass unsere Anwendungsklasse nur den Dienst verwendet., Es initialisiert nicht den Dienst, der zu einer besseren „Trennung der Bedenken“führt. Die Verwendung der Serviceschnittstelle ermöglicht es uns auch, die Anwendung einfach zu testen, indem wir den MessageService verspotten und die Dienste zur Laufzeit und nicht zur Kompilierungszeit binden.
Jetzt sind wir bereit, Java Dependency Injector-Klassen zu schreiben, die den Dienst und auch Consumer-Klassen initialisieren.
Java Dependency Injection – Injektoren Klassen
wir haben eine Schnittstelle MessageServiceInjector
mit der Deklaration dieser Methode, dass gibt die Consumer
Klasse.,
package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;public interface MessageServiceInjector {public Consumer getConsumer();}
Jetzt müssen wir für jeden Dienst Injektorklassen wie folgt erstellen.
package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;import com.journaldev.java.dependencyinjection.service.EmailServiceImpl;public class EmailServiceInjector implements MessageServiceInjector {@Overridepublic Consumer getConsumer() {return new MyDIApplication(new EmailServiceImpl());}}
package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;import com.journaldev.java.dependencyinjection.service.SMSServiceImpl;public class SMSServiceInjector implements MessageServiceInjector {@Overridepublic Consumer getConsumer() {return new MyDIApplication(new SMSServiceImpl());}}
Nun wollen wir sehen, wie unsere Client-Anwendungen die Anwendung mit einem einfachen Programm verwenden.
Wie Sie sehen, sind unsere Anwendungsklassen nur für die Nutzung des Dienstes verantwortlich. Serviceklassen werden in Injektoren erstellt. Wenn wir unsere Anwendung weiter erweitern müssen, um Facebook-Nachrichten zuzulassen, müssen wir nur Dienstklassen und Injektorklassen schreiben.,
Die Implementierung von Dependency Injection löste das Problem mit der fest codierten Abhängigkeit und half uns, unsere Anwendung flexibel und einfach zu erweitern. Lassen Sie uns nun sehen, wie einfach wir unsere Anwendungsklasse testen können, indem wir die Injektor-und Serviceklassen verspotten.
Java Dependency Injection-JUnit-Testfall mit Mock Injector und Service
Wie Sie sehen, verwende ich anonyme Klassen, um die Injektor-und Service-Klassen zu verspotten, und ich kann meine Anwendungsmethoden einfach testen., Ich verwende JUnit 4 für die obige Testklasse, stellen Sie also sicher, dass es sich in Ihrem Projekt-Build-Pfad befindet, wenn Sie über der Testklasse ausgeführt werden.
Wir haben Konstruktoren verwendet, um die Abhängigkeiten in die Anwendungsklassen einzufügen, eine andere Möglichkeit besteht darin, eine Setter-Methode zum Einfügen von Abhängigkeiten in Anwendungsklassen zu verwenden. Für die Setter-Methodenabhängigkeitsinjektion wird unsere Anwendungsklasse wie folgt implementiert.
package com.journaldev.java.dependencyinjection.injector;import com.journaldev.java.dependencyinjection.consumer.Consumer;import com.journaldev.java.dependencyinjection.consumer.MyDIApplication;import com.journaldev.java.dependencyinjection.service.EmailServiceImpl;public class EmailServiceInjector implements MessageServiceInjector {@Overridepublic Consumer getConsumer() {MyDIApplication app = new MyDIApplication();app.setService(new EmailServiceImpl());return app;}}
Eines der besten Beispiele für setter dependency injection sind Struts2 Servlet API Aware Interfaces.,
Ob konstruktorbasierte Abhängigkeitsinjektion oder Setter-basierte Verwendung ist eine Entwurfsentscheidung und hängt von Ihren Anforderungen ab. Wenn meine Anwendung beispielsweise ohne die Serviceklasse überhaupt nicht funktionieren kann, würde ich konstruktorbasiertes DI bevorzugen, oder ich würde setter methodenbasiertes DI verwenden, um es nur dann zu verwenden, wenn es wirklich benötigt wird.
Dependency Injection in Java ist eine Möglichkeit, eine Inversion der Kontrolle (IoC) in unserer Anwendung zu erreichen, indem Objekte von der Kompilierungszeit zur Laufzeit verschoben werden., Wir können das IoC auch durch Fabrikmuster, Entwurfsmuster für Vorlagenmethoden, Strategiemuster und Servicesuchmuster erreichen.
Spring Dependency Injection, Google Guice-und Java EE-CDI-frameworks erleichtern den Prozess der dependency injection durch die Verwendung von Java Reflection-API und java-Annotationen. Alles, was wir brauchen, ist, das Feld, den Konstruktor oder die Setter-Methode mit Anmerkungen zu versehen und sie in Konfigurations-XML-Dateien oder-Klassen zu konfigurieren.,
Einige der Vorteile der Verwendung von Dependency Injection in Java sind:
- Trennung von Bedenken
- Boilerplate-Code Reduzierung in Anwendungsklassen, da alle Arbeiten zum Initialisieren von Abhängigkeiten von der Injektorkomponente erledigt werden
- Konfigurierbare Komponenten machen die Anwendung leicht erweiterbar
- Unit-Tests sind einfach mit Mock-Objekten
Nachteile der Java Dependency Injection
Java Dependency Injection hat auch einige Nachteile:
- Bei Überbeanspruchung kann dies zu Wartungsproblemen führen, da die Auswirkungen von Änderungen zur Laufzeit bekannt sind.,
- Dependency injection in Java verbirgt die Abhängigkeiten der Dienstklasse, die zu Laufzeitfehlern führen können, die zur Kompilierungszeit abgefangen wurden.
Das ist alles für Abhängigkeitsinjektionsmuster in Java. Es ist gut, es zu wissen und zu verwenden, wenn wir die Kontrolle über die Dienste haben.