Angular依赖注入深度解析 (2026年03月27日) 依赖注入(DI)概述 依赖注入是Angular的核心特性之一,它是一种设计模式,用于实现控制反转(IoC)。DI使得类之间的依赖关系由容器(Injector)管理,而不是由类自身创建依赖对象。这种模式提高了代码的可测试性、可维护性和可扩展性。 Angular DI系统架构 Injector(注入器) 注入器是Angular DI系统的核心,负责创建和管理依赖项的实例。Angular在启动时会创建一个层级注入器树。 Provider(提供者) Provider告诉注入器如何创建或获取依赖项。Provider是注册依赖项的配置对象。 Token(令牌) Token是依赖项的唯一标识符,注入器通过Token查找对应的Provider。
依赖注入是Angular的核心特性之一,它是一种设计模式,用于实现控制反转(IoC)。DI使得类之间的依赖关系由容器(Injector)管理,而不是由类自身创建依赖对象。这种模式提高了代码的可测试性、可维护性和可扩展性。
注入器是Angular DI系统的核心,负责创建和管理依赖项的实例。Angular在启动时会创建一个层级注入器树。
Provider告诉注入器如何创建或获取依赖项。Provider是注册依赖项的配置对象。
Token是依赖项的唯一标识符,注入器通过Token查找对应的Provider。
// 最常见的Provider类型 providers: [ { provide: UserService, useClass: UserService } ] // 简写形式 providers: [UserService]
// 提供固定值 export const API_CONFIG = { baseUrl: 'https://api.example.com', timeout: 5000 }; providers: [ { provide: 'API_CONFIG', useValue: API_CONFIG } ] // 使用InjectionToken import { InjectionToken } from '@angular/core'; export const API_CONFIG = new InjectionToken<any>('api.config'); providers: [ { provide: API_CONFIG, useValue: { baseUrl: 'https://api.example.com' } } ]
// 使用工厂函数创建依赖 export function createLogger(config: AppConfig) { return new Logger(config.enableDebug); } providers: [ { provide: AppConfig, useValue: { enableDebug: true } }, { provide: Logger, useFactory: createLogger, deps: [AppConfig] } ]
// 为现有服务创建别名 providers: [ { provide: UserService, useClass: UserService }, { provide: 'IUserService', useExisting: UserService } ]
// 标记服务为可注入的服务 @Injectable({ providedIn: 'root' // 注册到根注入器 }) export class UserService { constructor(private http: HttpClient) {} }
// 注入非类类型的依赖 import { Inject, Injectable } from '@angular/core'; @Injectable() export class ApiService { constructor( @Inject(API_CONFIG) private config: { baseUrl: string } ) {} get url() { return this.config.baseUrl; } }
// 标记可选依赖 export class MyComponent { constructor( @Optional() private logger?: LoggerService ) {} }
export class ChildComponent { constructor( @Self() private localService: LocalService, // 只查看自身的注入器 @SkipSelf() private parentService: ParentService, // 跳过自身,从父级开始查找 @Host() private hostService: HostService // 限制在宿主元素范围内 ) {} }
// 在模块级别提供服务 @NgModule({ providers: [UserService] // 注册到模块注入器 }) export class AppModule {}
// 在组件级别提供服务 @Component({ selector: 'app-root', providers: [LoggerService], // 仅对该组件及其子组件可见 template: '...' }) export class AppComponent {}
Angular v14+引入了新的注入器层级结构:
@NgModule.providers或@Injectable({providedIn})注册@Component.providers或@Directive.providers注册解析顺序:ElementInjector(自身)→ ElementInjector(父级)→ ModuleInjector
// user.service.ts @Injectable({ providedIn: 'root' }) export class UserService { private users$ = new BehaviorSubject<User[]>([]); constructor(private http: HttpClient) {} getUsers(): Observable<User[]> { return this.http.get<User[]>('/api/users').pipe( tap(users => this.users$.next(users)) ); } getUserById(id: number): Observable<User> { return this.http.get<User>(`/api/users/${id}`); } createUser(user: User): Observable<User> { return this.http.post<User>('/api/users', user).pipe( tap(newUsers => this.getUsers().subscribe()) ); } }
// user-list.component.ts @Component({ selector: 'app-user-list', template: ` <div *ngFor="let user of users | async"> {{ user.name }} </div> ` }) export class UserListComponent implements OnInit { users$: Observable<User[]>; constructor(private userService: UserService) {} ngOnInit() { this.users$ = this.userService.getUsers(); } }
// auth.service.ts @Injectable({ providedIn: 'root' }) export class AuthService { constructor(private http: HttpClient) {} login(credentials: Credentials): Observable<Token> { return this.http.post<Token>('/api/login', credentials).pipe( tap(token => localStorage.setItem('token', token.value)) ); } } // data.service.ts @Injectable({ providedIn: 'root' }) export class DataService { constructor( private http: HttpClient, private authService: AuthService // 依赖AuthService ) {} getData(): Observable<any> { const token = localStorage.getItem('token'); const headers = new HttpHeaders().set('Authorization', `Bearer ${token}`); return this.http.get('/api/data', { headers }); } }
// 便捷注入装饰器 export function InjectConfig(configKey: string) { return function(target: any, key: string | symbol | undefined, index: number) { const originalType = Reflect.getMetadata('design:paramtypes', target)[index]; Object.defineProperty(target, key, { get() { const config = this.injector.get(APP_CONFIG); return config[configKey]; } }); }; } // 使用自定义装饰器 export class MyComponent { constructor(@InjectConfig('apiUrl') public apiUrl: string) {} }
// 创建类型安全的InjectionToken import { InjectionToken } from '@angular/core'; interface AppConfig { apiUrl: string; enableDebug: boolean; } export const APP_CONFIG = new InjectionToken<AppConfig>('app.config'); // 在模块中提供 @NgModule({ providers: [ { provide: APP_CONFIG, useValue: { apiUrl: 'https://api.example.com', enableDebug: true } as AppConfig } ] }) export class AppModule {} // 在组件中注入 export class MyComponent { constructor(@Inject(APP_CONFIG) private config: AppConfig) {} }
// TestBed配置 describe('UserService', () => { let service: UserService; let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [UserService] }); service = TestBed.inject(UserService); httpMock = TestBed.inject(HttpTestingController); }); afterEach(() => { httpMock.verify(); }); it('should get users', () => { const mockUsers = [{ id: 1, name: 'John' }]; service.getUsers().subscribe(users => { expect(users).toEqual(mockUsers); }); const req = httpMock.expectOne('/api/users'); req.flush(mockUsers); }); });
服务注册位置
@Injectable({providedIn: 'root'})@NgModule.providers中注册@Component.providers中注册依赖项设计原则
性能优化
providedIn: 'root'实现单例服务,自动tree-shaking可测试性
TestBed进行单元测试类型安全
InjectionToken提供类型检查root注入器root注入器读取@NgModule.providers和@Injectable({providedIn})注册的ProviderAngular的依赖注入系统是其强大功能的基石,掌握DI对于开发可维护、可测试的Angular应用至关重要。