Dagger — фреймворк для внедрения зависимостей (Dependency Injection, DI) в приложения на платформе Java. Разрабатывался компанией Square, но сейчас поддерживается Google.
Документация: https://dagger.dev/dev-guide/
Github: https://square.github.io/dagger/
Очень примитивный пример: https://github.com/cherepakhin/dagger_simple
Hello World: https://github.com/cherepakhin/dagger_hello_world
Задачи Dagger
- Автоматическое внедрение зависимостей в объекты (классы, интерфейсы, контексты и другие объекты);
- Управление жизненным циклом зависимостей;
- Создание синглтонов (единственных экземпляров) или одноразовых зависимостей (создаются новые экземпляры при каждом запросе);
- Обработка сложных зависимостей;
- Модульное тестирование (возможность заменять реальные зависимости на фиктивные или подставные объекты).
Особенности
- проверяет зависимости на этапе компиляции, в отличие от некоторых других фреймворков, которые используют рефлексию;
- генерирует код, который обрабатывает создание и предоставление зависимостей в соответствии с определёнными правилами;
Аннотации
Dagger использует аннотации, чтобы пометить классы и методы, которые участвуют в процессе внедрения зависимостей. Некоторые распространённые аннотации:
- @Module — отмечает модули и классы программного средства (com.sample.app.modules.DependenciesProviderModule.java) (аннотация класса).
- @Provides — этой аннотацией помечаются методы предоставления зависимостей внутри модулей (com.sample.app.modules.DependenciesProviderModule.java) (аннотация метода).
- @Named - используется вместе с @Provides для установки имени предоставляемого бина
и в классе, который использует зависимость:
@dagger.Provides @javax.inject.Named("sql") // предоставление зависимости с именем "sql" public static DataSource provideMySqlDataSource() {...}@Inject public DataPrinter(@Named("sql") com.sample.app.interfaces.DataSource sqlSource, @Named("file") com.sample.app.interfaces.DataSource fileSource) { ... } - @Component — используется для интерфейса, который объединяет части процесса внедрения зависимостей (com.sample.app.components.DataPrinterComponent.java) (аннотация класса).
- @Inject — метка запроса зависимостей, которые должны быть предоставлены фреймворком для внедрения. Может использоваться с конструктором класса, полями класса или методами (com.sample.app.util.DataPrinter.java) (аннотация метода).
Дополнительно понадобятся аннотации из javax.inject:
- @Inject - для конструкторов и полей классов (аннотация метода)
- @Singleton - для синглтонов @Provides (аннотация метода)
Introduction to Dagger 2 (www.baeldung.com)
Использование на примере
Hello world: https://github.com/cherepakhin/dagger_hello_world
- @Module — (см.использование ниже в @Provides) отмечает модули и классы программного средства @dagger.Module DependenciesProviderModule.java.
- @Provides — этой аннотацией помечаются методы предоставления зависимостей внутри модулей (@dagger.Module DependenciesProviderModule.java).
package com.sample.app.modules; import javax.inject.Named; import com.sample.app.interfaces.DataSource; import com.sample.app.interfaces.impl.FileDataSource; import com.sample.app.interfaces.impl.MySQLDataSource; import dagger.Module; import dagger.Provides; /** * Предоставляет реализации зависимостей с именами "file" и "sql" * зависимости используется в DataPrinter */ @Module public class DependenciesProviderModule { // Реализация зависимости и внесение в контекст (@dagger.Provides) с именем "sql" (@Named("sql")) // используется в DataPrinter через @Inject --> @javax.inject.Named("sql") DataSource sqlSource @Provides // @Provides - для внесения зависимости в контекст @Named("sql") // внесение в контекст bean с именем "sql" public static DataSource provideMySqlDataSource() { return new MySQLDataSource(); } @Provides @Named("file") public static DataSource provideFileDataSource() { return new FileDataSource(); } } - @Component — интерфейс, который объединяет части процесса внедрения зависимостей
@Component
DataPrinterComponentpackage com.sample.app.components; import com.sample.app.modules.DependenciesProviderModule; import com.sample.app.util.DataPrinter; import dagger.Component; import dagger.Module; // Используется в App.java как: // DataPrinterComponent dataPrinterComponent = DaggerDataPrinterComponent.builder().build(); // Реализация В DependenciesProviderModule.java так: // @Module // public class DependenciesProviderModule @Component(modules = {DependenciesProviderModule.class}) public interface DataPrinterComponent { DataPrinter dataPrinter(); } - @Inject — метка зависимостей, которые должны быть предоставлены фреймворком для внедрения. Может использоваться с конструктором класса, полями класса или методами DataPrinter.java. (@Named - используется для точного указания имени зависимости, т.к. в контексте две реализации одного интерфейса)
package com.sample.app.util; import javax.inject.Inject; import javax.inject.Named; public class DataPrinter { private com.sample.app.interfaces.DataSource sqlSource; private com.sample.app.interfaces.DataSource fileSource; // В конструктор инжектируются (@javax.inject) 2 бина с @Named("sql") и @Named("file") // Предоставляет их DependenciesProviderModule через @Provides(@dagger.Provides) // с именами (@Named("sql") и @Named("file")) @Inject public DataPrinter(@Named("sql") com.sample.app.interfaces.DataSource sqlSource, @Named("file") com.sample.app.interfaces.DataSource fileSource) { this.sqlSource = sqlSource; this.fileSource = fileSource; } public void print() { System.out.println("------------------------\nDataPrinter.print:"); try { System.out.println("dataFromSQL: " + getDataFromSQL()); } catch (Exception e) { throw new RuntimeException(e); } try { System.out.println("dataFromFile: " + getDataFromFile()); } catch (Exception e) { throw new RuntimeException(e); } } public String getDataFromSQL() throws Exception { if (sqlSource == null) { throw new Exception("sqlSource is null"); } return sqlSource.read(); } public String getDataFromFile() throws Exception { if (fileSource == null) { throw new Exception("fileSource is null"); } return fileSource.read(); } }
@Module DependenciesProviderModule.java объявляет два сервиса @Provides @Named("sql") и @Provides @Named("file"). Эти сервисы используются в com.sample.app.util.DataPrinter (см.выше). И вызываются в src/main/java/com/sample/app/App.java:
public class App {
public static void main(String[] args) {
// DaggerDataPrinterComponent - generated class by Dagger from interface DataPrinterComponent
DataPrinterComponent dataPrinterComponent = DaggerDataPrinterComponent.builder().build();
DataPrinter dataPrinter = dataPrinterComponent.dataPrinter();
dataPrinter.print();
}
}
Ссылки: