依赖注入 #
一、依赖注入概述 #
依赖注入(DI)是一种设计模式,用于实现控制反转(IoC),将依赖的创建和管理交给框架处理。
text
传统方式 依赖注入方式
┌─────────────────┐ ┌─────────────────┐
│ 组件 │ │ 组件 │
│ │ │ │
│ service = new │ │ constructor( │
│ Service() │ │ private svc │
│ │ │ ) │
└─────────────────┘ └────────┬────────┘
↓ ↓
自己创建依赖 ┌─────────────────┐
│ 注入器 │
│ 自动创建注入 │
└─────────────────┘
二、核心概念 #
2.1 注入器(Injector) #
注入器负责创建和管理依赖实例。
typescript
// Angular内部维护注入器树
RootInjector
├── ModuleInjector (模块级)
│ └── ComponentInjector (组件级)
│ └── ComponentInjector
└── ...
2.2 提供者(Provider) #
提供者告诉注入器如何创建实例。
typescript
// 类型提供者(最常用)
providers: [UserService]
// 等价于
providers: [
{ provide: UserService, useClass: UserService }
]
2.3 令牌(Token) #
令牌用于标识依赖项。
typescript
// 类型令牌
{ provide: UserService, useClass: UserService }
// 字符串令牌(不推荐)
{ provide: 'API_URL', useValue: 'https://api.example.com' }
// InjectionToken(推荐)
export const API_URL = new InjectionToken<string>('API_URL');
{ provide: API_URL, useValue: 'https://api.example.com' }
三、提供者类型 #
3.1 类提供者 #
typescript
// 直接使用类
providers: [UserService]
// 使用useClass
providers: [
{ provide: UserService, useClass: UserService }
]
// 使用不同的实现
providers: [
{ provide: LoggerService, useClass: ConsoleLoggerService }
]
// 条件提供
providers: [
{
provide: LoggerService,
useClass: environment.production
? ProductionLoggerService
: ConsoleLoggerService
}
]
3.2 值提供者 #
typescript
providers: [
{ provide: API_URL, useValue: 'https://api.example.com' },
{
provide: APP_CONFIG,
useValue: {
apiUrl: 'https://api.example.com',
timeout: 30000
}
}
]
3.3 工厂提供者 #
typescript
providers: [
{
provide: UserService,
useFactory: (http: HttpClient, config: AppConfig) => {
return new UserService(http, config.apiUrl);
},
deps: [HttpClient, APP_CONFIG]
}
]
// 条件工厂
providers: [
{
provide: LoggerService,
useFactory: () => {
if (environment.production) {
return new ProductionLoggerService();
}
return new ConsoleLoggerService();
}
}
]
3.4 别名提供者 #
typescript
providers: [
OldUserService,
{ provide: NewUserService, useExisting: OldUserService }
]
四、注入层级 #
4.1 层级注入器 #
text
PlatformInjector (平台级)
│
└── RootInjector (根注入器)
│
├── ModuleInjector (模块级)
│ │
│ └── ComponentInjector (组件级)
│ │
│ └── ComponentInjector
│
└── ...
4.2 providedIn配置 #
typescript
// 根注入器(全局单例)
@Injectable({
providedIn: 'root'
})
export class GlobalService { }
// 平台注入器(跨应用共享)
@Injectable({
providedIn: 'platform'
})
export class PlatformService { }
// 任何注入器(懒加载模块独立实例)
@Injectable({
providedIn: 'any'
})
export class FeatureService { }
// 特定模块
@Injectable({
providedIn: UserModule
})
export class ModuleService { }
4.3 组件级注入 #
typescript
@Component({
selector: 'app-user',
template: '...',
providers: [UserService] // 每个组件实例独立的服务实例
})
export class UserComponent {
constructor(private userService: UserService) {}
}
4.4 模块级注入 #
typescript
@NgModule({
providers: [UserService]
})
export class UserModule { }
五、依赖注入进阶 #
5.1 @Inject装饰器 #
typescript
import { Inject } from '@angular/core';
@Component({
selector: 'app-example',
template: '...'
})
export class ExampleComponent {
constructor(
@Inject(API_URL) private apiUrl: string,
@Inject(APP_CONFIG) private config: AppConfig
) {}
}
5.2 @Optional装饰器 #
typescript
import { Optional } from '@angular/core';
@Component({
selector: 'app-example',
template: '...'
})
export class ExampleComponent {
constructor(
@Optional() private logger?: LoggerService
) {
if (this.logger) {
this.logger.log('Logger available');
}
}
}
5.3 @Self装饰器 #
只在当前注入器查找:
typescript
import { Self } from '@angular/core';
@Component({
selector: 'app-example',
template: '...',
providers: [UserService]
})
export class ExampleComponent {
constructor(
@Self() private userService: UserService
) {}
}
5.4 @SkipSelf装饰器 #
跳过当前注入器,从父级开始查找:
typescript
import { SkipSelf } from '@angular/core';
@Component({
selector: 'app-child',
template: '...'
})
export class ChildComponent {
constructor(
@SkipSelf() private parentService: ParentService
) {}
}
5.5 @Host装饰器 #
在宿主组件处停止查找:
typescript
import { Host } from '@angular/core';
@Directive({
selector: '[appHighlight]'
})
export class HighlightDirective {
constructor(
@Host() private hostComponent: HostComponent
) {}
}
5.6 组合使用 #
typescript
constructor(
@Optional() @SkipSelf() private service?: MyService
) {
this.service = service ?? new DefaultService();
}
六、InjectionToken #
6.1 创建InjectionToken #
typescript
import { InjectionToken } from '@angular/core';
// 简单类型
export const API_URL = new InjectionToken<string>('API_URL');
// 复杂类型
export interface AppConfig {
apiUrl: string;
timeout: number;
theme: 'light' | 'dark';
}
export const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG');
// 带描述
export const FEATURE_FLAGS = new InjectionToken<FeatureFlags>(
'FeatureFlags',
{
providedIn: 'root',
factory: () => ({
featureA: true,
featureB: false
})
}
);
6.2 使用InjectionToken #
typescript
// 提供值
@NgModule({
providers: [
{ provide: API_URL, useValue: 'https://api.example.com' },
{
provide: APP_CONFIG,
useValue: {
apiUrl: 'https://api.example.com',
timeout: 30000,
theme: 'light'
}
}
]
})
export class AppModule { }
// 注入使用
@Injectable({ providedIn: 'root' })
export class ApiService {
constructor(
@Inject(API_URL) private apiUrl: string,
@Inject(APP_CONFIG) private config: AppConfig
) {}
}
6.3 带工厂的InjectionToken #
typescript
export const LOCAL_STORAGE = new InjectionToken<Storage>(
'LocalStorage',
{
providedIn: 'root',
factory: () => window.localStorage
}
);
export const WINDOW = new InjectionToken<Window>(
'Window',
{
providedIn: 'root',
factory: () => window
}
);
// 使用
@Injectable({ providedIn: 'root' })
export class StorageService {
constructor(
@Inject(LOCAL_STORAGE) private storage: Storage
) {}
setItem(key: string, value: string) {
this.storage.setItem(key, value);
}
}
七、多提供者 #
7.1 multi提供者 #
typescript
export const LOG_HANDLER = new InjectionToken<LogHandler>('LogHandler');
@NgModule({
providers: [
{ provide: LOG_HANDLER, useClass: ConsoleLogHandler, multi: true },
{ provide: LOG_HANDLER, useClass: FileLogHandler, multi: true },
{ provide: LOG_HANDLER, useClass: RemoteLogHandler, multi: true }
]
})
export class AppModule { }
7.2 注入多个值 #
typescript
@Injectable()
export class LogService {
constructor(
@Inject(LOG_HANDLER) private handlers: LogHandler[]
) {}
log(message: string) {
this.handlers.forEach(handler => handler.handle(message));
}
}
7.3 HTTP拦截器示例 #
typescript
@NgModule({
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: LoggingInterceptor,
multi: true
},
{
provide: HTTP_INTERCEPTORS,
useClass: CacheInterceptor,
multi: true
}
]
})
export class AppModule { }
八、循环依赖解决 #
8.1 使用forwardRef #
typescript
import { forwardRef } from '@angular/core';
@Injectable()
export class ServiceA {
constructor(
@Inject(forwardRef(() => ServiceB))
private serviceB: ServiceB
) {}
}
@Injectable()
export class ServiceB {
constructor(private serviceA: ServiceA) {}
}
8.2 使用Injector #
typescript
@Injectable()
export class ServiceA {
private serviceB: ServiceB;
constructor(private injector: Injector) {}
doSomething() {
if (!this.serviceB) {
this.serviceB = this.injector.get(ServiceB);
}
this.serviceB.doOther();
}
}
8.3 重构避免循环依赖 #
typescript
// 提取共享逻辑到独立服务
@Injectable()
export class SharedService { }
@Injectable()
export class ServiceA {
constructor(private shared: SharedService) {}
}
@Injectable()
export class ServiceB {
constructor(private shared: SharedService) {}
}
九、依赖注入最佳实践 #
9.1 使用providedIn: ‘root’ #
typescript
// 推荐
@Injectable({
providedIn: 'root'
})
export class UserService { }
// 不推荐(除非需要模块级作用域)
@NgModule({
providers: [UserService]
})
export class UserModule { }
9.2 使用InjectionToken #
typescript
// 推荐
export const API_URL = new InjectionToken<string>('API_URL');
// 不推荐
providers: [
{ provide: 'apiUrl', useValue: '...' }
]
9.3 避免循环依赖 #
typescript
// 重构服务结构,提取共享逻辑
// 或使用Injector延迟获取
9.4 合理使用作用域 #
| 场景 | 推荐方式 |
|---|---|
| 全局共享服务 | providedIn: 'root' |
| 模块独立服务 | providedIn: FeatureModule |
| 组件独立状态 | 组件级providers |
十、总结 #
| 概念 | 说明 |
|---|---|
| Injector | 创建和管理依赖实例 |
| Provider | 定义如何创建实例 |
| Token | 标识依赖项 |
@Inject |
注入特定Token |
@Optional |
可选依赖 |
@Self |
当前注入器查找 |
@SkipSelf |
跳过当前注入器 |
@Host |
宿主处停止查找 |
| InjectionToken | 类型安全的注入令牌 |
| multi | 多提供者 |
下一步:路由基础
最后更新:2026-03-26