Wprowadzenie do Daggera 2

1. Wstęp

W tym samouczku przyjrzymy się Dagger 2 - szybkiemu i lekkiemu frameworkowi do wstrzykiwania zależności.

Struktura jest dostępna zarówno dla języka Java, jak i dla systemu Android, ale wysoka wydajność wynikająca z wstrzykiwania w czasie kompilacji sprawia, że ​​jest to wiodące rozwiązanie dla tego drugiego.

2. Zastrzyk zależności

Dla przypomnienia, Dependency Injection jest konkretnym zastosowaniem bardziej ogólnej zasady Inversion of Control, w której przepływ programu jest kontrolowany przez sam program.

Jest implementowany za pomocą zewnętrznego komponentu, który zapewnia wystąpienia obiektów (lub zależności) potrzebnych innym obiektom.

Różne platformy implementują iniekcję zależności na różne sposoby. W szczególności jedną z najbardziej zauważalnych różnic jest to, czy wstrzykiwanie odbywa się w czasie wykonywania, czy w czasie kompilacji.

DI w czasie wykonywania zwykle opiera się na odbiciu, które jest prostsze w użyciu, ale wolniejsze w czasie wykonywania. Przykładem środowiska wykonawczego DI jest Spring.

Z drugiej strony DI czasu kompilacji opiera się na generowaniu kodu. Oznacza to, że wszystkie ciężkie operacje są wykonywane podczas kompilacji. DI w czasie kompilacji zwiększa złożoność, ale generalnie działa szybciej.

Dagger 2 należy do tej kategorii.

3. Konfiguracja Maven / Gradle

Aby użyć sztyletu w projekcie, musimy dodać zależność sztyletu do naszego pom.xml :

 com.google.dagger dagger 2.16 

Ponadto musimy również dołączyć kompilator Dagger używany do konwersji naszych klas z adnotacjami na kod używany do wstrzykiwań:

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

Przy tej konfiguracji Maven wyprowadzi wygenerowany kod do celu / wygenerowanych-źródeł / adnotacji .

Z tego powodu prawdopodobnie będziemy musieli dalej konfigurować nasze IDE, jeśli chcemy użyć któregokolwiek z jego funkcji uzupełniania kodu. Niektóre IDE mają bezpośrednie wsparcie dla procesorów adnotacji, podczas gdy inne mogą wymagać od nas dodania tego katalogu do ścieżki budowania.

Alternatywnie, jeśli używamy Androida z Gradle, możemy uwzględnić obie zależności:

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

Teraz, gdy mamy Dagger w naszym projekcie, stwórzmy przykładową aplikację, aby zobaczyć, jak to działa.

4. Wdrożenie

W naszym przykładzie spróbujemy zbudować samochód, wstrzykując jego komponenty.

Teraz Dagger używa standardowych adnotacji JSR-330 w wielu miejscach, z których jednym jest @Inject.

Możemy dodać adnotacje do pól lub konstruktora. Ale ponieważ Dagger nie obsługuje wstrzykiwania na polach prywatnych , przejdziemy do wstrzyknięcia konstruktora, aby zachować hermetyzację:

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 }

Następnie zaimplementujemy kod do wykonania wstrzyknięcia. Dokładniej stworzymy:

  • moduł , który jest klasa, która dostarcza lub buduje zależności obiektów i
  • składnik , który jest gniazdo przeznaczone do generowania wtryskiwacz

Złożone projekty mogą zawierać wiele modułów i komponentów, ale ponieważ mamy do czynienia z bardzo podstawowym programem, wystarczy jeden z nich.

Zobaczmy, jak je wdrożyć.

4.1. Moduł

Aby stworzyć moduł, musimy dodać do klasy adnotację @Module . Ta adnotacja wskazuje, że klasa może udostępniać zależności kontenerowi:

@Module public class VehiclesModule { }

Następnie musimy dodać adnotację @Provides do metod, które konstruują nasze zależności :

@Module public class VehiclesModule { @Provides public Engine provideEngine() { return new Engine(); } @Provides @Singleton public Brand provideBrand() { return new Brand("Baeldung"); } }

Zwróć też uwagę, że możemy skonfigurować zakres danej zależności. W tym przypadku nadajemy zakres singleton naszej instancji Brand, aby wszystkie instancje samochodu miały ten sam obiekt marki.

4.2. Składnik

Idąc dalej, stworzymy nasz interfejs komponentu . Jest to klasa, która będzie generować instancje Car, wstrzykując zależności dostarczane przez VehiclesModule .

Mówiąc najprościej, potrzebujemy sygnatury metody, która zwraca Car i musimy oznaczyć klasę adnotacją @Component :

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

Zwróć uwagę, jak przekazaliśmy naszą klasę modułu jako argument do adnotacji @Component . Gdybyśmy tego nie zrobili, Dagger nie wiedziałby, jak zbudować zależności samochodu.

Ponadto, ponieważ nasz moduł udostępnia obiekt singleton, musimy nadać ten sam zakres naszemu komponentowi, ponieważ Dagger nie pozwala komponentom bez zakresu odwoływać się do powiązań z zakresem .

4.3. Kod klienta

Wreszcie, możemy uruchomić kompilację mvn , aby uruchomić procesory adnotacji i wygenerować kod wtryskiwacza.

Następnie znajdziemy implementację komponentu o tej samej nazwie co interfejs, z prefiksem „ 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. Wiosenne analogie

Ci, którzy znają Spring, mogli zauważyć pewne podobieństwa między tymi dwoma frameworkami.

Sztyletu @Module adnotacja sprawia, że pojemnik świadomy klasy w bardzo podobny sposób, jak każdy z adnotacjami stereotypu wiosną (na przykład @Service , @Controller ...). Podobnie @Provides i @Component są prawie równoważne sprężyny @Bean i @Lookup odpowiednio.

Spring ma również swoją adnotację @Scope , korelującą z @Singleton , chociaż zauważ już tutaj kolejną różnicę w tym, że Spring domyślnie zakłada pojedynczy zakres, podczas gdy Dagger domyślnie przyjmuje to, co programiści Spring mogą nazywać zakresem prototypu, wywołując metodę dostawcy za każdym razem zależność jest wymagana.

6. Wniosek

W tym artykule omówiliśmy, jak skonfigurować i używać Dagger 2 na podstawowym przykładzie. Rozważaliśmy również różnice między iniekcją w czasie wykonywania i w czasie kompilacji.

Jak zawsze, cały kod w artykule jest dostępny na GitHub.