Изучение

Начало работы

Конфигурация, разрешение и закрытие небольшого контейнера Ark DI.

v1.2.1Начальный уровеньark_di

Безопасная версия SDK

Для сборки и распространения приложений используйте Dart 3.13.7+ или Flutter 3.47.8+. Это первые исправленные stable-версии для инцидента eMudhra; в дальнейшем выбирайте актуальный поддерживаемый SDK с исправлениями безопасности.

Минимальная версия в pubspec описывает совместимость API, а не безопасность старой среды исполнения. Пакеты проверены на Dart 3.13.7 и Flutter 3.47.8 без изменения публичного API. Новая версия библиотеки не исправляет уже установленное приложение: затронутые Android, Windows и Linux приложения нужно пересобрать и распространить заново.

Проверьте SDK в IDE, локальной сборке и CI. Обновление глобального SDK на компьютере не гарантирует, что конкретный проект или CI использует именно его. Не отключайте проверку сертификатов для обхода ошибок TLS.

На этой странице создаётся небольшой граф объектов с тремя разными временами жизни. Важно не только получить CatalogService, но и понимать, какой scope создаёт, удерживает и закрывает каждый объект.

1. Добавьте пакет

Терминал
shell
dart pub add ark_di
dart
import 'package:ark_di/ark_di.dart';

2. Не связывайте прикладные объекты с контейнером

Зависимости остаются обычными параметрами конструкторов:

dart
final class AppConfig {
  const AppConfig(this.apiBaseUrl);

  final Uri apiBaseUrl;
}

final class ApiClient {
  ApiClient(this.config);

  final AppConfig config;

  Future<void> close() async {}
}

final class CatalogService {
  CatalogService(this.client);

  final ApiClient client;
}

Эти классы не импортируют Ark DI и не обращаются к глобальному Service Locator. Способ сборки графа известен только корню композиции приложения.

3. Один раз сконфигурируйте граф

dart
final AppConfig config = AppConfig(Uri.parse('https://api.example.com'));

final DiContainer container = DiContainer.build((binder) {
  binder.bindInstance<AppConfig>(config);
  binder.bindLazySingleton<ApiClient>(
    (resolver) => ApiClient(resolver.get<AppConfig>()),
    dispose: (client) => client.close(),
  );
  binder.bindFactory<CatalogService>(
    (resolver) => CatalogService(resolver.get<ApiClient>()),
  );
});

Регистрации задают разное время жизни:

РегистрацияПоведение
bindInstanceСохраняет переданный AppConfig; по умолчанию контейнер владеет регистрацией.
bindLazySingletonПри первом разрешении создаёт один ApiClient, кэширует его и вызывает disposer при закрытии.
bindFactoryПри каждом разрешении создаёт новый CatalogService и не удерживает его.

Обратный вызов конфигурации выполняется один раз. После его завершения DiBinder становится недействительным, поэтому код приложения не может незаметно менять регистрации.

4. Разрешите граф на границе композиции

dart
final CatalogService first = container.get<CatalogService>();
final CatalogService second = container.get<CatalogService>();

assert(!identical(first, second));
assert(identical(first.client, second.client));

Сервисы остаются временными объектами, но оба получают один принадлежащий контейнеру клиент. Затем приложение передаёт first нужной функции через обычный конструктор.

5. Закройте владельца

dart
await container.close();

При закрытии контейнер ожидает активные разрешения, закрывает дочерние scope и освобождает принадлежащие ему кэшированные объекты в порядке зависимостей. Результаты фабрик он не закрывает, потому что не удерживает их: ресурсами временного объекта владеет его потребитель.

Перед использованием дочерних scope и асинхронных регистраций прочитайте руководство по корню композиции.