← Назад к вопросам

Какие знаешь аннотации в Dagger позволяющие добавить класс в граф зависимостей?

2.0 Middle🔥 131 комментариев
#Dependency Injection

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какие знаешь аннотации в Dagger позволяющие добавить класс в граф зависимостей

В Dagger есть несколько способов добавить класс в граф зависимостей. Это основа для работы dependency injection. Расскажу о всех основных аннотациях.

1. @Inject на конструктор

Самый простой и рекомендуемый способ. Dagger автоматически использует конструктор для создания экземпляра.

class UserRepository @Inject constructor(
    private val apiService: ApiService,
    private val database: AppDatabase
) {
    // Dagger автоматически создаст этот класс
    // и внедрит зависимости
}

class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var userRepository: UserRepository
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // DaggerActivityComponent.inject(this)
    }
}

Преимущества:

  • Простота и читаемость
  • Dagger автоматически генерирует код
  • Поддержка всех зависимостей конструктора
  • Работает с Hilt out-of-the-box

2. @Provides в Module

Для создания сложных объектов или если конструктор с @Inject недостаточен.

@Module
class NetworkModule {
    
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }
    
    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    
    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

Когда использовать:

  • Создание конфигурированных объектов (Retrofit, OkHttp)
  • Объекты из внешних библиотек
  • Сложная логика инициализации
  • Нужен выбор между разными реализациями

3. @Binds в Module

Для связывания interface с его реализацией. Более эффективен, чем @Provides.

interface UserRepository {
    suspend fun getUser(id: Long): User
}

@Inject
class UserRepositoryImpl(
    private val apiService: ApiService
) : UserRepository {
    override suspend fun getUser(id: Long): User {
        return apiService.fetchUser(id)
    }
}

@Module
abstract class RepositoryModule {
    
    @Binds
    abstract fun bindUserRepository(
        userRepositoryImpl: UserRepositoryImpl
    ): UserRepository
}

Преимущества:

  • Один строка вместо полного @Provides метода
  • Меньше код (без лишней логики)
  • Более читаемо
  • Dagger не генерирует дополнительный код

4. @Multibinds (для коллекций)

Для добавления нескольких реализаций в граф.

@Module
abstract class InterceptorModule {
    @Binds
    @IntoSet
    abstract fun bindAuthInterceptor(
        impl: AuthInterceptor
    ): Interceptor
    
    @Binds
    @IntoSet
    abstract fun bindLoggingInterceptor(
        impl: LoggingInterceptor
    ): Interceptor
}

@Module
class NetworkModule {
    @Provides
    fun provideOkHttpClient(
        interceptors: Set<Interceptor>
    ): OkHttpClient {
        return OkHttpClient.Builder()
            .apply {
                interceptors.forEach { addInterceptor(it) }
            }
            .build()
    }
}

5. @IntoMap (для Map зависимостей)

Создание Map с разными реализациями.

@MapKey
annotation class ApiKeyQualifier(val value: String)

interface ApiFactory {
    fun create(): ApiService
}

@Module
abstract class ApiModule {
    
    @Binds
    @IntoMap
    @ApiKeyQualifier("v1")
    abstract fun bindApiV1(impl: ApiV1): ApiFactory
    
    @Binds
    @IntoMap
    @ApiKeyQualifier("v2")
    abstract fun bindApiV2(impl: ApiV2): ApiFactory
}

class ApiManager @Inject constructor(
    private val apiFactories: Map<String, @JvmSuppressWildcards ApiFactory>
) {
    fun getApi(version: String): ApiService {
        return apiFactories[version]?.create()
            ?: throw IllegalArgumentException("Unknown API version")
    }
}

6. Qualifier аннотации

Для различения нескольких реализаций одного типа.

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class LoggingEnabled

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
annotation class MockApi

@Module
class ApiModule {
    @Provides
    @Singleton
    @LoggingEnabled
    fun provideLoggingApi(okHttpClient: OkHttpClient): ApiService {
        return ApiService(okHttpClient, loggingEnabled = true)
    }
    
    @Provides
    @MockApi
    fun provideMockApi(): ApiService {
        return MockApiService()
    }
}

class MyViewModel @Inject constructor(
    @LoggingEnabled private val api: ApiService
) {
    // Получит реализацию с логированием
}

7. @BindsOptional

Для опциональных зависимостей.

@Module
abstract class AnalyticsModule {
    @Binds
    @BindsOptional
    abstract fun bindAnalytics(impl: FirebaseAnalytics): Analytics
}

class MyViewModel @Inject constructor(
    private val analytics: Optional<Analytics>
) {
    fun trackEvent(name: String) {
        analytics.ifPresent { it.track(name) }
    }
}

8. Scope аннотации

Для управления жизненным циклом объектов.

@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class ActivityScope

@ActivityScope
@Component(modules = [ActivityModule::class])
interface ActivityComponent {
    fun inject(activity: MainActivity)
}

@ActivityScope
class UserRepository @Inject constructor(
    private val apiService: ApiService
) {
    // Синглтон на уровне Activity
}

9. Hilt аннотации

Модернизированный Dagger с предустановленными scope.

@HiltViewModel
class MyViewModel @Inject constructor(
    private val userRepository: UserRepository
) : ViewModel() {}

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private val viewModel: MyViewModel by viewModels()
}

Сравнение аннотаций

АннотацияКогда использоватьПреимущества
@Inject constructorПростые классыПростота, автоматизм
@ProvidesСложные объектыКонтроль, конфигурация
@BindsInterface реализацииКомпактно, эффективно
@IntoSet/@IntoMapМножественные реализацииГибкость, масштабируемость
QualifierРазные реализации одного типаРазличие, ясность
@BindsOptionalОпциональные зависимостиБезопасность

Лучшие практики

  1. Используй @Inject на конструктор в первую очередь
  2. @Provides только для сложных объектов
  3. @Binds вместо @Provides для interface
  4. Избегай циклических зависимостей
  5. Используй Scopes для управления жизненным циклом
  6. Prefer Hilt в новых проектах (вместо чистого Dagger)

Это основные способы добавления классов в граф зависимостей Dagger. Выбор аннотации зависит от сложности инициализации и требований проекта.