В Angular инъекция зависимостей — один из ключевых механизмов, который позволяет эффективно управлять зависимостями в приложении. Токены инъекции играют важную роль в этом процессе, позволяя Angular правильно разрешать и инжектировать объекты и сервисы.
Токен инъекции — это механизм, который позволяет Angular узнавать, какой именно объект или сервис требуется инжектировать в компоненты или другие сервисы. Токен выступает в качестве уникального идентификатора для различных зависимостей в контексте инъекции зависимостей.
В Angular инъекция зависимостей основана на токенах, которые
используются для разрешения конкретных объектов, предназначенных для
внедрения. На практике это чаще всего выполняется через типы классов, но
в некоторых случаях может использоваться более сложная настройка через
InjectionToken.
В стандартной практике, когда Angular пытается разрешить зависимость,
он использует тип класса как токен. Например, если компонент или сервис
требует инъекции сервиса UserService, Angular будет
использовать класс UserService как токен. Таким образом,
объект, который предоставляется для инъекции, будет совпадать с типом
этого класса.
Пример инъекции зависимости через токен:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor() {}
getUser() {
return { name: 'John Doe', age: 30 };
}
}
import { Component } from '@angular/core';
import { UserService } from './user.service';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
})
export class UserComponent {
constructor(private userService: UserService) {}
ngOnInit() {
const user = this.userService.getUser();
console.log(user);
}
}
В этом примере UserService автоматически используется
как токен для инъекции в компонент UserComponent.
InjectionToken:
пользовательские токеныВ Angular, помимо стандартных токенов, также существует возможность
создания пользовательских токенов через класс
InjectionToken. Это полезно, если
требуется внедрить зависимость, которая не имеет конкретного типа или
если нужно создать более гибкие, динамичные механизмы инъекции.
InjectionToken позволяет Angular
разрешать зависимости, которые не могут быть автоматически разрешены
через типы классов, например, конфигурации или интерфейсы. Это особенно
полезно, когда нужно передавать данные, которые не являются экземплярами
классов, или когда типы зависимостей не могут быть использованы
напрямую.
Пример использования InjectionToken:
import { InjectionToken, Injectable, Inject } from '@angular/core';
// Создание токена
export const APP_CONFIG = new InjectionToken<Config>('app.config');
// Тип конфигурации
export interface Config {
apiEndpoint: string;
debugMode: boolean;
}
@Injectable({
providedIn: 'root'
})
export class ConfigService {
constructor(@Inject(APP_CONFIG) private config: Config) {}
getConfig() {
return this.config;
}
}
В этом примере создаётся токен APP_CONFIG, который
используется для инъекции конфигурационных данных в сервис
ConfigService.
Для того чтобы Angular знал, как разрешать зависимости через токены, необходимо определить провайдеры. Провайдеры могут быть настроены для предоставления конкретных значений или объектов для инъекции.
Для токенов, таких как InjectionToken, провайдеры могут
быть указаны в @NgModule, @Component, или в
сервисах. Провайдер может содержать инструкцию, как создать или передать
объект, связанный с токеном.
Пример настройки провайдера:
import { NgModule } from '@angular/core';
const appConfig: Config = {
apiEndpoint: 'https://api.example.com',
debugMode: true
};
@NgModule({
providers: [
{ provide: APP_CONFIG, useValue: appConfig }
]
})
export class AppModule {}
В этом примере объект конфигурации appConfig передаётся
в качестве значения для токена APP_CONFIG. Это значение
будет инжектироваться в любые сервисы или компоненты, где требуется
конфигурация.
Использование токенов инъекции особенно полезно в сложных сценариях, когда требуется внедрить различные виды объектов в зависимости от контекста. Например, можно создать несколько различных провайдеров для одного и того же токена, и Angular будет использовать тот, который соответствует текущему контексту.
Пример условной инъекции:
const devConfig: Config = {
apiEndpoint: 'https://dev-api.example.com',
debugMode: true
};
const prodConfig: Config = {
apiEndpoint: 'https://prod-api.example.com',
debugMode: false
};
@NgModule({
providers: [
{
provide: APP_CONFIG,
useValue: environment.production ? prodConfig : devConfig
}
]
})
export class AppModule {}
Здесь значение конфигурации будет зависеть от режима работы приложения — для продакшн-режима будет использован один объект конфигурации, для разработки — другой.
При использовании ленивой загрузки (lazy loading) Angular создаёт свои собственные инстансы для каждого модуля, и для каждого инстанса может быть настроен отдельный провайдер с использованием различных токенов. Это позволяет контролировать, как и какие данные или сервисы инжектируются в зависимости от контекста, когда используется ленивое или динамическое внедрение модулей.
@NgModule({
imports: [RouterModule.forChild(routes)],
providers: [
{ provide: APP_CONFIG, useValue: lazyLoadedConfig }
]
})
export class LazyLoadedModule {}
Таким образом, каждый модуль может иметь свои собственные провайдеры для токенов, которые инжектируются только в его компоненты или сервисы.
Токены инъекции играют важную роль в построении гибкой архитектуры приложений на Angular. Правильное использование токенов позволяет разделять ответственность, улучшать тестируемость и обеспечить масштабируемость приложения. Они упрощают работу с зависимостями, делая код более модульным и легким для сопровождения.
Независимо от того, используются ли стандартные токены или
пользовательские через InjectionToken, важно помнить, что
они являются частью системы управления зависимостями, которая лежит в
основе большинства современных Angular-приложений.