VSCode依赖注入源码目录结构
1234567891011121314151617📦src ┣ 📂vs ┃ ┣ 📂platform ┃ ┃ ┣ 📂instantiation ┃ ┃ ┃ ┣ 📂common ┃ ┃ ┃ ┃ ┣ 📜descriptors.ts // 依赖描述符 ┃ ┃ ┃ ┃ ┣ 📜extensions.ts // 插件系统和装饰器 ┃ ┃ ┃ ┃ ┣ 📜graph.ts // 依赖关系图 ┃ ┃ ┃ ┃ ┣ 📜instantiation.ts // 依赖注入类型和装饰器 ┃ ┃ ┃ ┃ ┣ 📜instantiationService.ts // 实例化服务 ┃ ┃ ┃ ┃ ┗ 📜serviceCollection.ts // 服务收集 ┃ ┃ ┃ ┗ 📂test ┃ ┃ ┃ ┃ ┗ 📂common ┃ ┃ ┃ ┃ ┃ ┣ 📜graph.test.ts // 依赖关系图单元测试 ┃ ┃ ┃ ┃ ┃ ┣ 📜instantiationService.test.ts // 实例化服务单元测试 ┃ ┃ ┃ ┃ ┃ ┗ 📜instantiationServiceMock.ts // 实例化服务模拟
本篇不剖析底层代码,只讲怎么用,想研究架构的可以参考下面文章
底层原理
📚 目录
核心概念
什么是依赖注入?
依赖注入是一种设计模式,它将对象的创建和依赖关系的管理交给外部容器处理,而不是在对象内部硬编码依赖。
这套DI系统的关键要素
- ServiceIdentifier:服务的唯一标识符(通常由
createDecorator创建) - SyncDescriptor:服务的描述符,包含构造函数和参数
- ServiceCollection:服务注册表,存储所有服务
- InstantiationService:实例化引擎,负责创建和管理服务实例
快速开始
1. 导入核心模块
123456789import {
InstantiationService,
ServiceCollection,
SyncDescriptor,
registerSingleton,
InstantiationType,
createDecorator
} from './core/instantiation';
2. 定义服务接口和标识符
123456789// 定义服务接口
export interface ILoggerService {
log(message: string): void;
error(message: string): void;
}
// 创建服务标识符(这是关键!)
export const ILoggerService = createDecorator<ILoggerService>('loggerService');
3. 实现服务
1234567891011// 实现服务类
export class LoggerService implements ILoggerService {
log(message: string): void {
console.log(`[LOG] ${message}`);
}
error(message: string): void {
console.error(`[ERROR] ${message}`);
}
}
4. 注册服务
12345678910111213// 方式一:使用 registerSingleton
registerSingleton(
ILoggerService,
LoggerService,
InstantiationType.Delayed // 延迟实例化(推荐)
);
// 方式二:使用 ServiceCollection + InstantiationService
const serviceCollection = new ServiceCollection();
serviceCollection.set(ILoggerService, new SyncDescriptor(LoggerService));
const instantiationService = new InstantiationService(serviceCollection);
5. 使用服务
123456789101112131415// 创建需要依赖注入的类
export class App {
constructor(
@ILoggerService private readonly logger: ILoggerService
) {}
run() {
this.logger.log('应用启动成功!');
}
}
// 通过 InstantiationService 创建实例
const app = instantiationService.createInstance(App);
app.run(); // 输出:[LOG] 应用启动成功!
核心API详解
1. createDecorator<T>(serviceId: string): ServiceIdentifier<T>
创建服务标识符,用于标识和注入服务。
1234// 定义服务标识符
export const IUserService = createDecorator<IUserService>('userService');
export const IConfigService = createDecorator<IConfigService>('configService');
2. registerSingleton(id, ctor, instantiationType)
注册单例服务到全局注册表。
12345678import { registerSingleton, InstantiationType } from './core/instantiation';
// 立即实例化(启动时创建)
registerSingleton(ILoggerService, LoggerService, InstantiationType.Eager);
// 延迟实例化(首次使用时创建,推荐)
registerSingleton(IUserService, UserService, InstantiationType.Delayed);
3. SyncDescriptor<T>
服务的描述符,用于描述如何创建服务实例。
123456789101112import { SyncDescriptor } from './core/instantiation';
// 基本用法
const descriptor = new SyncDescriptor(LoggerService);
// 带静态参数
const descriptorWithArgs = new SyncDescriptor(
UserService,
['staticArg1', 'staticArg2'], // 静态参数
true // 支持延迟实例化
);
4. ServiceCollection
服务注册表容器,存储服务的实例或描述符。
123456789101112131415161718import { ServiceCollection } from './core/instantiation';
const collection = new ServiceCollection();
// 注册服务实例(已实例化)
collection.set(ILoggerService, new LoggerService());
// 注册服务描述符(延迟实例化)
collection.set(IUserService, new SyncDescriptor(UserService));
// 检查服务是否已注册
if (collection.has(ILoggerService)) {
const service = collection.get(ILoggerService);
}
// 覆盖已注册的服务
const oldService = collection.set(ILoggerService, new MockLoggerService());
5. InstantiationService
核心实例化服务,负责创建和管理所有服务实例。
1234567891011121314151617181920import { InstantiationService, ServiceCollection } from './core/instantiation';
// 创建根实例化服务
const rootServices = new ServiceCollection();
const instantiationService = new InstantiationService(rootServices);
// 创建子实例化服务(可覆盖部分服务)
const childServices = new ServiceCollection();
childServices.set(IConfigService, new SyncDescriptor(MockConfigService));
const childInstantiationService = instantiationService.createChild(childServices);
// 创建实例
const myService = instantiationService.createInstance(MyService);
// 调用函数并注入服务
instantiationService.invokeFunction((accessor) => {
const logger = accessor.get(ILoggerService);
logger.log('通过 invokeFunction 调用');
});
实战示例
示例1:用户管理系统
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465// ============ 1. 定义服务接口和标识符 ============
export interface IUserService {
getUser(id: string): Promise<User>;
saveUser(user: User): Promise<void>;
}
export const IUserService = createDecorator<IUserService>('userService');
export interface IAuthService {
login(username: string, password: string): Promise<string>;
logout(): void;
}
export const IAuthService = createDecorator<IAuthService>('authService');
// ============ 2. 实现服务 ============
export class UserService implements IUserService {
private users = new Map<string, User>();
async getUser(id: string): Promise<User> {
return this.users.get(id) || null;
}
async saveUser(user: User): Promise<void> {
this.users.set(user.id, user);
}
}
export class AuthService implements IAuthService {
constructor(
@IUserService private userService: IUserService
) {}
async login(username: string, password: string): Promise<string> {
// 验证逻辑
const token = `token_${Date.now()}`;
return token;
}
logout(): void {
console.log('用户已登出');
}
}
// ============ 3. 注册服务 ============
registerSingleton(IUserService, UserService, InstantiationType.Delayed);
registerSingleton(IAuthService, AuthService, InstantiationType.Delayed);
// ============ 4. 使用服务 ============
export class LoginController {
constructor(
@IAuthService private authService: IAuthService,
@IUserService private userService: IUserService
) {}
async handleLogin(username: string, password: string) {
const token = await this.authService.login(username, password);
const user = await this.userService.getUser(username);
return { token, user };
}
}
// 在应用入口
const instantiationService = new InstantiationService(new ServiceCollection());
const controller = instantiationService.createInstance(LoginController);
await controller.handleLogin('john', 'password123');
示例2:事件驱动架构
12345678910111213141516171819202122232425262728293031323334353637383940414243444546// ============ 事件服务 ============
export interface IEventService {
emit(event: string, data: any): void;
on(event: string, handler: Function): void;
}
export const IEventService = createDecorator<IEventService>('eventService');
export class EventService implements IEventService {
private handlers = new Map<string, Function[]>();
emit(event: string, data: any): void {
const handlers = this.handlers.get(event) || [];
handlers.forEach(handler => handler(data));
}
on(event: string, handler: Function): void {
if (!this.handlers.has(event)) {
this.handlers.set(event, []);
}
this.handlers.get(event)!.push(handler);
}
}
// ============ 通知服务(依赖事件服务) ============
export interface INotificationService {
showSuccess(message: string): void;
showError(message: string): void;
}
export const INotificationService = createDecorator<INotificationService>('notificationService');
export class NotificationService implements INotificationService {
constructor(@IEventService private eventService: IEventService) {}
showSuccess(message: string): void {
this.eventService.emit('notification', { type: 'success', message });
}
showError(message: string): void {
this.eventService.emit('notification', { type: 'error', message });
}
}
// 注册服务
registerSingleton(IEventService, EventService, InstantiationType.Delayed);
registerSingleton(INotificationService, NotificationService, InstantiationType.Delayed);
高级用法
1. 循环依赖检测
DI系统会自动检测并报告循环依赖:
1234567891011// ❌ 错误的用法(会导致循环依赖)
export class ServiceA {
constructor(@IServiceB private serviceB: IServiceB) {}
}
export class ServiceB {
constructor(@IServiceA private serviceA: IServiceA) {}
}
// 实例化时会抛出 CyclicDependencyError
2. 服务覆盖(用于测试)
12345678910111213141516171819// 生产环境服务
class RealApiService implements IApiService {
async fetch(url: string) {
return fetch(url);
}
}
// Mock服务用于测试
class MockApiService implements IApiService {
async fetch(url: string) {
return { data: 'mock data' };
}
}
// 在测试环境中覆盖服务
const testServices = new ServiceCollection();
testServices.set(IApiService, new SyncDescriptor(MockApiService));
const testInstantiationService = instantiationService.createChild(testServices);
3. 延迟加载优化
12345678910111213// 使用 InstantiationType.Delayed 优化启动性能
registerSingleton(IHeavyService, HeavyService, InstantiationType.Delayed);
// 首次使用时才实例化
class App {
constructor(@IHeavyService private heavyService: IHeavyService) {}
async onUserAction() {
// 此时才会真正创建 HeavyService 实例
await this.heavyService.performHeavyTask();
}
}
4. 可选依赖
123456789101112131415// 使用 @optional 装饰器处理可选依赖
export class FeatureService {
constructor(
@IRequiredService private required: IRequiredService,
@optional(IExternalService) private external?: IExternalService
) {}
doWork() {
this.required.doMandatoryThing();
if (this.external) {
this.external.doOptionalThing();
}
}
}
常见问题
Q1: 为什么需要 createDecorator 创建标识符?
A: createDecorator 创建的服务标识符既是TypeScript装饰器,又是运行时的唯一标识。它让DI系统能够:
- 在编译时提供类型安全
- 在运行时识别要注入的服务
- 支持参数位置追踪
Q2: Eager 和 Delayed 模式如何选择?
A:
- Delayed(推荐):服务在首次使用时实例化,提升启动性能
- Eager:服务在容器创建时立即实例化,适用于必需的、轻量级的服务
Q3: 如何在React/Vue组件中使用?
A: 将 instantiationService 注入到组件上下文:
12345678910111213141516171819202122// React Context示例
const DI_Context = React.createContext<IInstantiationService>(null);
export const AppProvider = ({ children }) => {
const instantiationService = useMemo(() => {
const services = new ServiceCollection();
// 注册服务...
return new InstantiationService(services);
}, []);
return (
<DI_Context.Provider value={instantiationService}>
{children}
</DI_Context.Provider>
);
};
export const useService = <T,>(serviceId: ServiceIdentifier<T>): T => {
const instantiationService = useContext(DI_Context);
return instantiationService.invokeFunction(accessor => accessor.get(serviceId));
};
Q4: 如何调试依赖注入问题?
A: 启用跟踪功能(如果支持):
1234567// 在创建 InstantiationService 时启用跟踪
const instantiationService = new InstantiationService(
serviceCollection,
true // enableTracing
);
// 会输出详细的实例化日志,帮助定位问题
Q5: 可以动态注册服务吗?
A: 可以,但在实例化服务之前注册:
12345678// ✅ 正确:在创建实例前注册
serviceCollection.set(IMyService, new SyncDescriptor(MyService));
const instance = instantiationService.createInstance(MyComponent);
// ❌ 错误:实例化后注册可能无效
const instance = instantiationService.createInstance(MyComponent);
serviceCollection.set(IMyService, new SyncDescriptor(MyService)); // 已创建的实例不会重新注入
总结
这套VSCode风格的DI系统提供了:
✅ 类型安全:完全的TypeScript支持
✅ 性能优化:支持延迟实例化
✅ 循环依赖检测:自动检测并报错
✅ 层次化容器:支持服务覆盖和隔离
✅ 测试友好:轻松Mock服务
通过依赖注入,你的代码将更加:
- 可维护:依赖关系清晰可见
- 可测试:轻松替换为Mock对象
- 可扩展:添加新服务不影响现有代码
这份文档涵盖了从入门到实战的全部内容。建议你先从快速开始部分着手,在实际项目中逐步尝试,遇到具体问题再查阅对应章节。祝你使用愉快!🎉


全部评论 (0)
暂无评论,快来抢吧~