Files
esengine/packages/core/src/Core/ServiceContainer.ts

335 lines
8.7 KiB
TypeScript
Raw Normal View History

import { createLogger } from '../Utils/Logger';
const logger = createLogger('ServiceContainer');
/**
*
* ServiceContainer
*/
export interface IService {
/**
*
*
*/
dispose(): void;
}
/**
*
*/
export type ServiceType<T extends IService> = new (...args: unknown[]) => T;
/**
*
*/
export enum ServiceLifetime {
/**
* -
*/
Singleton = 'singleton',
/**
* -
*/
Transient = 'transient'
}
/**
*
*/
interface ServiceRegistration<T extends IService> {
/**
*
*/
type: ServiceType<T>;
/**
*
*/
instance?: T;
/**
*
*/
factory?: (container: ServiceContainer) => T;
/**
*
*/
lifetime: ServiceLifetime;
}
/**
*
*
*
*
*
*
* -
* -
* -
* -
*
* @example
* ```typescript
* const container = new ServiceContainer();
*
* // 注册单例服务
* container.registerSingleton(TimerManager);
*
* // 注册工厂函数
* container.registerSingleton(Logger, (c) => createLogger('App'));
*
* // 注册实例
* container.registerInstance(Config, new Config());
*
* // 解析服务
* const timer = container.resolve(TimerManager);
* ```
*/
export class ServiceContainer {
/**
*
*/
private _services: Map<ServiceType<IService>, ServiceRegistration<IService>> = new Map();
/**
*
*/
private _resolving: Set<ServiceType<IService>> = new Set();
/**
*
*
* @param type -
* @param factory -
*
* @example
* ```typescript
* // 直接注册类型
* container.registerSingleton(TimerManager);
*
* // 使用工厂函数
* container.registerSingleton(Logger, (c) => {
* return createLogger('App');
* });
* ```
*/
public registerSingleton<T extends IService>(
type: ServiceType<T>,
factory?: (container: ServiceContainer) => T
): void {
if (this._services.has(type as ServiceType<IService>)) {
logger.warn(`Service ${type.name} is already registered`);
return;
}
this._services.set(type as ServiceType<IService>, {
type: type as ServiceType<IService>,
factory: factory as ((container: ServiceContainer) => IService) | undefined,
lifetime: ServiceLifetime.Singleton
});
logger.debug(`Registered singleton service: ${type.name}`);
}
/**
*
*
*
*
* @param type -
* @param factory -
*
* @example
* ```typescript
* // 每次解析都创建新实例
* container.registerTransient(Command);
* ```
*/
public registerTransient<T extends IService>(
type: ServiceType<T>,
factory?: (container: ServiceContainer) => T
): void {
if (this._services.has(type as ServiceType<IService>)) {
logger.warn(`Service ${type.name} is already registered`);
return;
}
this._services.set(type as ServiceType<IService>, {
type: type as ServiceType<IService>,
factory: factory as ((container: ServiceContainer) => IService) | undefined,
lifetime: ServiceLifetime.Transient
});
logger.debug(`Registered transient service: ${type.name}`);
}
/**
*
*
*
*
* @param type -
* @param instance -
*
* @example
* ```typescript
* const config = new Config();
* container.registerInstance(Config, config);
* ```
*/
public registerInstance<T extends IService>(type: new (...args: any[]) => T, instance: T): void {
if (this._services.has(type as ServiceType<IService>)) {
logger.warn(`Service ${type.name} is already registered`);
return;
}
this._services.set(type as ServiceType<IService>, {
type: type as ServiceType<IService>,
instance: instance as IService,
lifetime: ServiceLifetime.Singleton
});
logger.debug(`Registered service instance: ${type.name}`);
}
/**
*
*
* @param type -
* @returns
* @throws
*
* @example
* ```typescript
* const timer = container.resolve(TimerManager);
* ```
*/
public resolve<T extends IService>(type: ServiceType<T>): T {
const registration = this._services.get(type as ServiceType<IService>);
if (!registration) {
throw new Error(`Service ${type.name} is not registered`);
}
// 检测循环依赖
if (this._resolving.has(type as ServiceType<IService>)) {
const chain = Array.from(this._resolving).map(t => t.name).join(' -> ');
throw new Error(`Circular dependency detected: ${chain} -> ${type.name}`);
}
// 如果是单例且已经有实例,直接返回
if (registration.lifetime === ServiceLifetime.Singleton && registration.instance) {
return registration.instance as T;
}
// 添加到解析栈
this._resolving.add(type as ServiceType<IService>);
try {
// 创建实例
let instance: IService;
if (registration.factory) {
// 使用工厂函数
instance = registration.factory(this);
} else {
// 直接构造
instance = new (registration.type)();
}
// 如果是单例,缓存实例
if (registration.lifetime === ServiceLifetime.Singleton) {
registration.instance = instance;
}
return instance as T;
} finally {
// 从解析栈移除
this._resolving.delete(type as ServiceType<IService>);
}
}
/**
*
*
* null而不是抛出异常
*
* @param type -
* @returns null
*
* @example
* ```typescript
* const timer = container.tryResolve(TimerManager);
* if (timer) {
* timer.schedule(...);
* }
* ```
*/
public tryResolve<T extends IService>(type: ServiceType<T>): T | null {
try {
return this.resolve(type);
} catch {
return null;
}
}
/**
*
*
* @param type -
* @returns
*/
public isRegistered<T extends IService>(type: ServiceType<T>): boolean {
return this._services.has(type as ServiceType<IService>);
}
/**
*
*
* @param type -
* @returns
*/
public unregister<T extends IService>(type: ServiceType<T>): boolean {
const registration = this._services.get(type as ServiceType<IService>);
if (!registration) {
return false;
}
// 如果有单例实例,调用 dispose
if (registration.instance) {
registration.instance.dispose();
}
this._services.delete(type as ServiceType<IService>);
logger.debug(`Unregistered service: ${type.name}`);
return true;
}
/**
*
*/
public clear(): void {
// 清理所有单例实例
for (const [, registration] of this._services) {
if (registration.instance) {
registration.instance.dispose();
}
}
this._services.clear();
logger.debug('Cleared all services');
}
/**
*
*
* @returns
*/
public getRegisteredServices(): ServiceType<IService>[] {
return Array.from(this._services.keys());
}
}