Einführung in den Dolch 2

Einführung in Dolch 2

1. Einführung

In diesem Tutorial werfen wir einen Blick auf Dagger 2 - ein schnelles und leichtes Framework für die Abhängigkeitsinjektion.

Das Framework ist sowohl für Java als auch für Android verfügbar. Aufgrund der hohen Leistung, die durch Injection während der Kompilierung erzielt wird, ist es jedoch eine führende Lösung für letztere.

2. Abhängigkeitsspritze

Zur Erinnerung:Dependency Injection ist eine konkrete Anwendung des allgemeineren Inversion of Control-Prinzips, bei dem der Programmfluss vom Programm selbst gesteuert wird.

Die Implementierung erfolgt über eine externe Komponente, die Instanzen von Objekten (oder Abhängigkeiten) bereitstellt, die von anderen Objekten benötigt werden.

Verschiedene Frameworks implementieren die Abhängigkeitsinjektion auf unterschiedliche Weise. Einer der bemerkenswertesten Unterschiede ist insbesondere, ob die Injektion zur Laufzeit oder zur Kompilierungszeit erfolgt.

Die Laufzeit-DI basiert normalerweise auf einer Reflektion, die einfacher zu verwenden ist, jedoch zur Laufzeit langsamer. Ein Beispiel füra run-time DI framework is Spring.

Die Kompilierungszeit DI basiert dagegen auf der Codegenerierung. Dies bedeutet, dass alle schweren Operationen während der Kompilierung ausgeführt werden. DI zur Kompilierungszeit erhöht die Komplexität, ist jedoch im Allgemeinen schneller.

Dolch 2 fällt in diese Kategorie.

3. Maven/Gradle Configuration

Um Dagger in einem Projekt verwenden zu können, müssen wirthe dagger dependency zu unserenpom.xml hinzufügen:


    com.google.dagger
    dagger
    2.16

Außerdem müssen wirinclude the Dagger compiler verwenden, um unsere mit Anmerkungen versehenen Klassen in den für die Injektionen verwendeten Code zu konvertieren:


    org.apache.maven.plugins
    maven-compiler-plugin
    3.6.1
    
         
              
                  com.google.dagger
                  dagger-compiler
                  2.16
              
         
    

Mit dieser Konfiguration gibt Maven den generierten Code intarget/generated-sources/annotations aus.

Aus diesem Grund istwe likely need to further configure our IDE, wenn wir eine der Code-Vervollständigungsfunktionen verwenden möchten. Einige IDEs unterstützen Annotation-Prozessoren direkt, andere müssen dieses Verzeichnis möglicherweise dem Erstellungspfad hinzufügen.

Wenn wir Android mit Gradle verwenden, können wir alternativ beide Abhängigkeiten einbeziehen:

compile 'com.google.dagger:dagger:2.16'
annotationProcessor 'com.google.dagger:dagger-compiler:2.16'

Nachdem wir Dagger in unserem Projekt haben, erstellen wir eine Beispielanwendung, um zu sehen, wie es funktioniert.

4. Implementierung

In unserem Beispiel werden wir versuchen, ein Auto zu bauen, indem wir seine Komponenten einspritzen.

Nun,Dagger uses the standard JSR-330 annotations an vielen Stellen, eine davon ist@Inject.

Wir können die Annotationen zu Feldern oder zum Konstruktor hinzufügen. DaDagger doesn’t support injection on private fields ist, werden wir uns für die Konstruktorinjektion entscheiden, um die Einkapselung zu erhalten:

public class Car {

    private Engine engine;
    private Brand brand;

    @Inject
    public Car(Engine engine, Brand brand) {
        this.engine = engine;
        this.brand = brand;
    }

    // getters and setters

}

Als Nächstes implementieren wir den Code, um die Injektion durchzuführen. Im Einzelnen erstellen wir:

  • amodule, eine Klasse, die die Abhängigkeiten der Objekte bereitstellt oder erstellt, und

  • acomponent, eine Schnittstelle zur Erzeugung des Injektors

Komplexe Projekte können mehrere Module und Komponenten enthalten. Da es sich jedoch um ein sehr einfaches Programm handelt, reicht jeweils eines aus.

Mal sehen, wie man sie implementiert.

4.1. Modul

Um ein Modul zu erstellen,we need to annotate the class with the @Module annotation. Diese Anmerkung gibt an, dass die Klasse Abhängigkeiten für den Container verfügbar machen kann:

@Module
public class VehiclesModule {
}

Dannwe need to add the @Provides annotation on methods that construct our dependencies:

@Module
public class VehiclesModule {
    @Provides
    public Engine provideEngine() {
        return new Engine();
    }

    @Provides
    @Singleton
    public Brand provideBrand() {
        return new Brand("example");
    }
}

Beachten Sie auch, dass wir den Umfang einer bestimmten Abhängigkeit konfigurieren können. In diesem Fall geben wir den Singleton-Bereich für unsereBrand-Instanz an, sodass alle Autoinstanzen dasselbe Markenobjekt verwenden.

4.2. Komponente

Im weiteren Verlauf erstellen wir unsere Komponentenschnittstelle. Dies ist die Klasse, die Car-Instanzen generiert und Abhängigkeiten vonVehiclesModule einfügt.

Einfach ausgedrückt, wir benötigen eine Methodensignatur, dieCar undwe need to mark the class with the @Component annotation zurückgibt:

@Singleton
@Component(modules = VehiclesModule.class)
public interface VehiclesComponent {
    Car buildCar();
}

Beachten Sie, wie wir unsere Modulklasse als Argument für die Annotation@Componentübergeben haben. If we didn’t do that, Dagger wouldn’t know how to build the car’s dependencies.

Da unser Modul ein Singleton-Objekt bereitstellt, müssen wir unserer Komponente denselben Bereich zuweisen, daDagger doesn’t allow for unscoped components to refer to scoped bindings.

4.3. Kundencode

Schließlich können wirmvn compile ausführen, um die Anmerkungsprozessoren auszulösen und den Injektorcode zu generieren.

Danach finden wir unsere Komponentenimplementierung mit demselben Namen wie die Schnittstelle, nur mit dem Präfix "Dagger":

@Test
public void givenGeneratedComponent_whenBuildingCar_thenDependenciesInjected() {
    VehiclesComponent component = DaggerVehiclesComponent.create();

    Car carOne = component.buildCar();
    Car carTwo = component.buildCar();

    Assert.assertNotNull(carOne);
    Assert.assertNotNull(carTwo);
    Assert.assertNotNull(carOne.getEngine());
    Assert.assertNotNull(carTwo.getEngine());
    Assert.assertNotNull(carOne.getBrand());
    Assert.assertNotNull(carTwo.getBrand());
    Assert.assertNotEquals(carOne.getEngine(), carTwo.getEngine());
    Assert.assertEquals(carOne.getBrand(), carTwo.getBrand());
}

5. Frühlingsanalogien

Diejenigen, die mit Spring vertraut sind, haben möglicherweise Parallelen zwischen den beiden Frameworks festgestellt.

Die Annotation@Modulevon Dagger macht den Container auf eine Klasse aufmerksam, die den stereotypen Annotationen von Spring sehr ähnlich ist (z. B.@Service,@Controller…). Ebenso entsprechen@Provides und@Component fast den@Bean und@Lookup von Spring.

Spring hat auch die@Scope-Annotation, die mit@Singleton korreliert. Beachten Sie hier jedoch bereits einen weiteren Unterschied darin, dass Spring standardmäßig einen Singleton-Bereich annimmt, während Dagger standardmäßig das verwendet, was Spring-Entwickler als Prototyp-Bereich bezeichnen und aufrufen die Anbietermethode jedes Mal, wenn eine Abhängigkeit erforderlich ist.

6. Fazit

In diesem Artikel haben wir anhand eines einfachen Beispiels erklärt, wie Sie Dagger 2 einrichten und verwenden. Wir haben auch die Unterschiede zwischen der Laufzeit- und der Kompilierzeitinjektion berücksichtigt.

Wie immer ist der gesamte Code im Artikelover on GitHub verfügbar.