HoRain云--Angular依赖注入全攻略
Angular依赖注入系统详解:从基础到高级实践 Angular的依赖注入是其核心特性,本文系统讲解了依赖注入的实现方式:1) 基础使用:创建可注入服务及组件注入;2) 提供者配置:根级别、模块级别和组件级别三种方式;3) 提供者类型:类提供者、值提供者、工厂提供者和别名提供者;4) 分层注入器实战;5) 高级应用包括HTTP拦截器和可选依赖;6) 测试技巧;7) 最佳实践如使用Injection

🎬 HoRain 云小助手:个人主页
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
目录

Angular 的依赖注入系统是其核心特性之一,非常强大和灵活。下面详细讲解如何在 Angular 中实现和使用依赖注入。
1. 基础概念和设置
创建可注入的服务
// user.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' // 在根注入器提供,整个应用单例
})
export class UserService {
private users: any[] = [];
getUsers() {
return this.users;
}
addUser(user: any) {
this.users.push(user);
}
}
在组件中注入服务
// user-list.component.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';
@Component({
selector: 'app-user-list',
template: `
<div *ngFor="let user of users">
{{ user.name }}
</div>
`
})
export class UserListComponent implements OnInit {
users: any[] = [];
// 通过构造函数注入
constructor(private userService: UserService) {}
ngOnInit() {
this.users = this.userService.getUsers();
}
}
2. 提供者的不同配置方式
1. 在根级别提供(推荐)
@Injectable({
providedIn: 'root' // 应用级单例
})
export class ApiService {
// 服务实现
}
2. 在模块级别提供
// app.module.ts
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [
UserService, // 模块级单例
{ provide: 'API_URL', useValue: 'https://api.example.com' }
],
bootstrap: [AppComponent]
})
export class AppModule { }
3. 在组件级别提供
@Component({
selector: 'app-user',
template: `...`,
providers: [UserService] // 组件级实例(每个组件都有自己的实例)
})
export class UserComponent {
constructor(private userService: UserService) {}
}
3. 不同类型的提供者
类提供者(最常用)
providers: [UserService]
// 等价于
providers: [{ provide: UserService, useClass: UserService }]
值提供者
// 提供常量或配置
providers: [
{ provide: 'API_CONFIG', useValue: {
baseUrl: 'https://api.example.com',
timeout: 5000
}},
{ provide: 'APP_VERSION', useValue: '1.0.0' }
]
// 注入使用
constructor(
@Inject('API_CONFIG') private config: any,
@Inject('APP_VERSION') private version: string
) {}
工厂提供者
// 根据条件创建不同的实例
export function loggerFactory(isProduction: boolean): LoggerService {
return isProduction ?
new ProductionLogger() :
new DevelopmentLogger();
}
providers: [
{ provide: 'IS_PRODUCTION', useValue: false },
{
provide: LoggerService,
useFactory: loggerFactory,
deps: ['IS_PRODUCTION'] // 依赖注入
}
]
别名提供者
// 为一个服务提供多个令牌
class AdvancedUserService extends UserService {
// 扩展功能
}
providers: [
AdvancedUserService,
{ provide: UserService, useExisting: AdvancedUserService } // 别名
]
4. 分层注入器实战
模块级服务
// shared.module.ts
@NgModule({
providers: [SharedService] // 在共享模块中提供
})
export class SharedModule { }
// feature.module.ts
@NgModule({
imports: [SharedModule],
providers: [FeatureService] // 在特性模块中提供
})
export class FeatureModule { }
组件树中的注入层次
// 父组件提供服务
@Component({
selector: 'app-parent',
template: `<app-child></app-child>`,
providers: [DataService] // 提供给所有子组件
})
export class ParentComponent {}
// 子组件可以注入
@Component({
selector: 'app-child',
template: `...`
})
export class ChildComponent {
constructor(private dataService: DataService) {} // 注入父组件提供的服务
}
5. 实际项目中的高级用法
配置服务
// config.service.ts
import { Injectable, InjectionToken } from '@angular/core';
export interface AppConfig {
apiUrl: string;
timeout: number;
retryCount: number;
}
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');
@Injectable({
providedIn: 'root'
})
export class ConfigService {
constructor(@Inject(APP_CONFIG) private config: AppConfig) {}
get apiUrl(): string {
return this.config.apiUrl;
}
get timeout(): number {
return this.config.timeout;
}
}
// 在模块中配置
@NgModule({
providers: [
{
provide: APP_CONFIG,
useValue: {
apiUrl: 'https://api.example.com',
timeout: 5000,
retryCount: 3
}
}
]
})
export class AppModule { }
HTTP 拦截器(依赖注入的典型应用)
// auth.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';
import { AuthService } from './auth.service';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
const authToken = this.authService.getToken();
const authReq = req.clone({
headers: req.headers.set('Authorization', `Bearer ${authToken}`)
});
return next.handle(authReq);
}
}
// 在模块中注册拦截器
@NgModule({
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true // 允许多个拦截器
}
]
})
export class AppModule { }
可选的依赖注入
import { Optional, SkipSelf } from '@angular/core';
@Component({...})
export class MyComponent {
// 如果服务不存在,不会报错,service 为 null
constructor(@Optional() private optionalService: OptionalService) {}
// 跳过自身查找器,从父注入器查找
constructor(@SkipSelf() private parentService: ParentService) {}
}
6. 测试中的依赖注入
单元测试中的模拟依赖
// user.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { UserService } from './user.service';
import { ApiService } from './api.service';
describe('UserService', () => {
let service: UserService;
let mockApiService: jasmine.SpyObj<ApiService>;
beforeEach(() => {
// 创建模拟服务
mockApiService = jasmine.createSpyObj('ApiService', ['getUsers']);
TestBed.configureTestingModule({
providers: [
UserService,
{ provide: ApiService, useValue: mockApiService } // 注入模拟对象
]
});
service = TestBed.inject(UserService);
});
it('应该从API获取用户', () => {
mockApiService.getUsers.and.returnValue([{id: 1, name: 'John'}]);
const users = service.getUsers();
expect(users.length).toBe(1);
expect(mockApiService.getUsers).toHaveBeenCalled();
});
});
7. 最佳实践和模式
1. 使用 InjectionToken 提供配置
// tokens.ts
import { InjectionToken } from '@angular/core';
export const API_BASE_URL = new InjectionToken<string>('API_BASE_URL');
export const LOG_LEVEL = new InjectionToken<'debug' | 'info' | 'error'>('LOG_LEVEL');
// 使用
providers: [
{ provide: API_BASE_URL, useValue: 'https://api.example.com' },
{ provide: LOG_LEVEL, useValue: 'debug' }
]
2. 分层服务架构
// 数据层服务
@Injectable({ providedIn: 'root' })
export class UserApiService {
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users');
}
}
// 业务逻辑层服务
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private userApi: UserApiService) {}
getActiveUsers(): Observable<User[]> {
return this.userApi.getUsers().pipe(
map(users => users.filter(user => user.active))
);
}
}
3. 环境特定的提供者
// environment.ts
export const environment = {
production: false,
apiUrl: 'https://dev.api.example.com'
};
// 根据环境提供不同的服务
const loggerServiceFactory = (environment: any) => {
return environment.production ?
new ProductionLogger() :
new DevelopmentLogger();
};
providers: [
{ provide: 'ENVIRONMENT', useValue: environment },
{
provide: LoggerService,
useFactory: loggerServiceFactory,
deps: ['ENVIRONMENT']
}
]
8. 常见问题解决
循环依赖问题
// 使用 @Inject 和 forwardRef 解决循环依赖
@Component({...})
export class ComponentA {
constructor(
@Inject(forwardRef(() => ComponentB)) private componentB: ComponentB
) {}
}
@Component({...})
export class ComponentB {
constructor(private componentA: ComponentA) {}
}
动态组件注入
// 在运行时动态创建组件并注入服务
export class DynamicComponentService {
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector
) {}
createDynamicComponent(componentType: Type<any>, parentInjector?: Injector) {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentType);
// 创建自定义注入器
const injector = Injector.create({
parent: parentInjector || this.injector,
providers: [
{ provide: DynamicDataService, useClass: DynamicDataService }
]
});
return componentFactory.create(injector);
}
}
依赖注入总结表
|
场景 |
推荐方式 |
说明 |
|---|---|---|
|
全局单例服务 |
|
应用级单例,推荐大多数服务使用 |
|
模块特定服务 |
在 |
模块级单例 |
|
组件树服务 |
在组件 |
组件及其子组件共享实例 |
|
配置值 |
使用 |
提供配置常量 |
|
条件创建 |
使用工厂提供者 |
根据运行时条件创建实例 |
|
测试模拟 |
在测试模块中覆盖提供者 |
使用 |
核心要点:
-
理解注入器层次结构 - 根注入器 → 模块注入器 → 组件注入器
-
选择合适的提供范围 - 根据服务的使用范围决定提供级别
-
善用各种提供者类型 - 类、值、工厂、别名等
-
测试友好 - 依赖注入使得测试时模拟依赖非常容易
-
避免循环依赖 - 使用
@Inject和forwardRef解决
Angular 的依赖注入系统是其框架的基石,正确使用可以创建出松耦合、可测试、可维护的应用程序。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙
更多推荐



所有评论(0)