Въведение в Dagger 2

1. Въведение

В този урок ще разгледаме Dagger 2 - бърза и лека инжекционна рамка за зависимост.

Рамката е достъпна както за Java, така и за Android, но високата производителност, получена от инжектирането по време на компилация, го прави водещо решение за последния.

2. Инжектиране на зависимост

Като малко напомняне, Dependency Injection е конкретно приложение на по-общия принцип на инверсия на контрола, при който потокът на програмата се контролира от самата програма.

Той се реализира чрез външен компонент, който осигурява екземпляри от обекти (или зависимости), необходими на други обекти.

И различните рамки прилагат инжектиране на зависимост по различни начини. По-специално, една от най-забележителните от тези разлики е дали инжектирането се случва по време на изпълнение или по време на компилация.

DI за изпълнение обикновено се основава на отражение, което е по-просто за използване, но по-бавно по време на изпълнение. Пример за изпълнение на DI рамка е Spring.

DI от време на компилация се основава на генериране на код. Това означава, че всички операции с тежко тегло се извършват по време на компилацията. DI за компилация добавя сложност, но като цяло се представя по-бързо.

Dagger 2 попада в тази категория.

3. Конфигурация на Maven / Gradle

За да използвате Dagger в проект, ние ще трябва да добавите кама зависимостта към нашия pom.xml :

 com.google.dagger dagger 2.16 

Освен това ще трябва да включим компилатора Dagger, използван за преобразуване на нашите анотирани класове в кода, използван за инжекциите:

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

С тази конфигурация Maven ще изведе генерирания код в целеви / генерирани източници / анотации .

Поради тази причина вероятно ще трябва да конфигурираме нашата IDE, ако искаме да използваме някоя от функциите за завършване на кода. Някои IDE имат директна поддръжка за процесори за анотиране, докато други може да се нуждаят от нас, за да добавим тази директория към пътя на компилация.

Като алтернатива, ако използваме Android с Gradle, можем да включим и двете зависимости:

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

Сега, когато имаме Dagger в нашия проект, нека създадем примерно приложение, за да видим как работи.

4. Изпълнение

За нашия пример ще се опитаме да изградим автомобил, като инжектираме компонентите му.

Сега Dagger използва стандартните анотации JSR-330 на много места, едното е @Inject.

Можем да добавяме поясненията към полета или конструктора. Но тъй като Dagger не поддържа инжектиране в частни полета , ще се спрем на инжектиране на конструктор, за да запазим капсулирането:

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 }

След това ще приложим кода, за да извършим инжектирането. По-конкретно, ще създадем:

  • един модул , който е клас, който осигурява или изгражда зависимости на обектите, както и
  • един компонент , който е интерфейс се използва за генериране на инжектора

Сложните проекти могат да съдържат множество модули и компоненти, но тъй като имаме работа с много основна програма, един от всеки е достатъчен.

Нека да видим как да ги приложим.

4.1. Модул

За да създадем модул, трябва да анотираме класа с анотацията @Module . Тази анотация показва, че класът може да направи зависимостите достъпни за контейнера:

@Module public class VehiclesModule { }

След това трябва да добавим анотацията @Provides за методи, които изграждат нашите зависимости :

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

Също така имайте предвид, че можем да конфигурираме обхвата на дадена зависимост. В този случай ние даваме обхвата на единицата на нашия екземпляр на марка, така че всички инстанции на автомобили споделят един и същ обект на марка.

4.2. Съставна част

Продължавайки, ще създадем нашия интерфейс за компоненти . Това е класът, който ще генерира автомобилни екземпляри, инжектирайки зависимости, предоставени от VehiclesModule .

Най-просто казано, ние се нуждаем от подпис на метод, който връща Car и трябва да маркираме класа с анотацията @Component :

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

Забележете как предадохме нашия модулен клас като аргумент на анотацията @Component . Ако не го направихме, Кинджал нямаше да знае как да изгради зависимостите на автомобила.

Освен това, тъй като нашият модул предоставя единичен обект, ние трябва да дадем същия обхват на нашия компонент, тъй като Dagger не позволява неразпределените компоненти да се отнасят до обхванати обвързвания .

4.3. Код на клиента

И накрая, можем да стартираме mvn compile, за да задействаме процесорите за анотиране и да генерираме инжекторния код.

След това ще намерим изпълнението на нашия компонент със същото име като интерфейса, просто с префикс „ 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. Пролетни аналогии

Запознатите с Spring може да са забелязали някои паралели между двете рамки.

@Module анотация на Dagger прави контейнера информиран за клас по много подобен начин като всеки от стереотипните анотации на Spring (например @Service , @Controller ...). По същия начин @Provides и @Component са почти еквивалентни на Spring @Bean и @Lookup съответно.

Spring също има своя анотация @Scope , корелираща с @Singleton , макар че тук имаме предвид още една разлика в това, че Spring по подразбиране приема единичен обхват, докато Dagger по подразбиране е това, което разработчиците на Spring могат да посочат като обхват на прототипа, извиквайки метода на доставчика всеки път, когато изисква се зависимост.

6. Заключение

В тази статия разгледахме как да настроим и използваме Dagger 2 с основен пример. Също така разгледахме разликите между времето на изпълнение и инжектирането по време на компилация.

Както винаги, целият код в статията е достъпен в GitHub.