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

454 lines
13 KiB
TypeScript
Raw Normal View History

import { createLogger } from '../Utils/Logger';
2025-10-10 21:52:43 +08:00
import { isUpdatable as checkUpdatable, getUpdatableMetadata } from './DI';
const logger = createLogger('ServiceContainer');
/**
*
* ServiceContainer
*/
export interface IService {
/**
*
*
*/
dispose(): void;
}
/**
*
2025-10-10 21:52:43 +08:00
*
* 便使
* 使 any[]
*/
2025-10-10 21:52:43 +08:00
export type ServiceType<T extends IService> = new (...args: any[]) => T;
/**
*
*
* Symbol
*/
export type ServiceIdentifier<T extends IService = IService> = ServiceType<T> | symbol;
/**
*
*/
export enum ServiceLifetime {
/**
* -
*/
Singleton = 'singleton',
/**
* -
*/
Transient = 'transient'
}
/**
*
*/
interface ServiceRegistration<T extends IService> {
/**
*
*/
identifier: ServiceIdentifier<T>;
/**
*
*/
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<ServiceIdentifier, ServiceRegistration<IService>> = new Map();
/**
*
*/
private _resolving: Set<ServiceIdentifier> = new Set();
2025-10-10 21:52:43 +08:00
/**
*
*
* 使@Updatable装饰器标记的服务Core统一更新
*
*/
private _updatableServices: Array<{ instance: IService; priority: number }> = [];
2025-10-10 21:52:43 +08:00
/**
*
*
* @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 ServiceIdentifier)) {
logger.warn(`Service ${type.name} is already registered`);
return;
}
this._services.set(type as ServiceIdentifier, {
identifier: type as ServiceIdentifier,
type: type as ServiceType<IService>,
...(factory && { factory: factory as (container: ServiceContainer) => IService }),
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 ServiceIdentifier)) {
logger.warn(`Service ${type.name} is already registered`);
return;
}
this._services.set(type as ServiceIdentifier, {
identifier: type as ServiceIdentifier,
type: type as ServiceType<IService>,
...(factory && { factory: factory as (container: ServiceContainer) => IService }),
lifetime: ServiceLifetime.Transient
});
logger.debug(`Registered transient service: ${type.name}`);
}
/**
*
*
*
*
* @param identifier - Symbol
* @param instance -
*
* @example
* ```typescript
* const config = new Config();
* container.registerInstance(Config, config);
*
* // 使用 Symbol 作为标识符(适用于接口)
* const IFileSystem = Symbol('IFileSystem');
* container.registerInstance(IFileSystem, new TauriFileSystem());
* ```
*/
public registerInstance<T extends IService>(identifier: ServiceIdentifier<T>, instance: T): void {
if (this._services.has(identifier)) {
const name = typeof identifier === 'symbol' ? identifier.description : identifier.name;
logger.warn(`Service ${name} is already registered`);
return;
}
this._services.set(identifier, {
identifier,
instance: instance as IService,
lifetime: ServiceLifetime.Singleton
});
2025-10-10 21:52:43 +08:00
// 如果使用了@Updatable装饰器添加到可更新列表
if (typeof identifier !== 'symbol' && checkUpdatable(identifier)) {
const metadata = getUpdatableMetadata(identifier);
2025-10-10 21:52:43 +08:00
const priority = metadata?.priority ?? 0;
this._updatableServices.push({ instance, priority });
// 按优先级排序(数值越小越先执行)
this._updatableServices.sort((a, b) => a.priority - b.priority);
logger.debug(`Service ${identifier.name} is updatable (priority: ${priority}), added to update list`);
2025-10-10 21:52:43 +08:00
}
const name = typeof identifier === 'symbol' ? identifier.description : identifier.name;
logger.debug(`Registered service instance: ${name}`);
}
/**
*
*
* @param identifier - Symbol
* @returns
* @throws
*
* @example
* ```typescript
* const timer = container.resolve(TimerManager);
*
* // 使用 Symbol
* const fileSystem = container.resolve(IFileSystem);
* ```
*/
public resolve<T extends IService>(identifier: ServiceIdentifier<T>): T {
const registration = this._services.get(identifier);
const name = typeof identifier === 'symbol' ? identifier.description : identifier.name;
if (!registration) {
throw new Error(`Service ${name} is not registered`);
}
// 检测循环依赖
if (this._resolving.has(identifier)) {
const chain = Array.from(this._resolving).map((t) =>
typeof t === 'symbol' ? t.description : t.name
).join(' -> ');
throw new Error(`Circular dependency detected: ${chain} -> ${name}`);
}
// 如果是单例且已经有实例,直接返回
if (registration.lifetime === ServiceLifetime.Singleton && registration.instance) {
return registration.instance as T;
}
// 添加到解析栈
this._resolving.add(identifier);
try {
// 创建实例
let instance: IService;
if (registration.factory) {
// 使用工厂函数
instance = registration.factory(this);
} else if (registration.type) {
// 直接构造
instance = new (registration.type)();
} else {
throw new Error(`Service ${name} has no factory or type to construct`);
}
// 如果是单例,缓存实例
if (registration.lifetime === ServiceLifetime.Singleton) {
registration.instance = instance;
2025-10-10 21:52:43 +08:00
// 如果使用了@Updatable装饰器添加到可更新列表
if (registration.type && checkUpdatable(registration.type)) {
2025-10-10 21:52:43 +08:00
const metadata = getUpdatableMetadata(registration.type);
const priority = metadata?.priority ?? 0;
this._updatableServices.push({ instance, priority });
// 按优先级排序(数值越小越先执行)
this._updatableServices.sort((a, b) => a.priority - b.priority);
logger.debug(`Service ${name} is updatable (priority: ${priority}), added to update list`);
2025-10-10 21:52:43 +08:00
}
}
return instance as T;
} finally {
// 从解析栈移除
this._resolving.delete(identifier);
}
}
/**
*
*
* null而不是抛出异常
*
* @param identifier - Symbol
* @returns null
*
* @example
* ```typescript
* const timer = container.tryResolve(TimerManager);
* if (timer) {
* timer.schedule(...);
* }
* ```
*/
public tryResolve<T extends IService>(identifier: ServiceIdentifier<T>): T | null {
try {
return this.resolve(identifier);
} catch {
return null;
}
}
/**
*
*
* @param identifier - Symbol
* @returns
*/
public isRegistered<T extends IService>(identifier: ServiceIdentifier<T>): boolean {
return this._services.has(identifier);
}
/**
*
*
* @param identifier - Symbol
* @returns
*/
public unregister<T extends IService>(identifier: ServiceIdentifier<T>): boolean {
const registration = this._services.get(identifier);
if (!registration) {
return false;
}
// 如果有单例实例,调用 dispose
if (registration.instance) {
2025-10-10 21:52:43 +08:00
// 从可更新列表中移除
const index = this._updatableServices.findIndex((item) => item.instance === registration.instance);
2025-10-10 21:52:43 +08:00
if (index !== -1) {
this._updatableServices.splice(index, 1);
}
registration.instance.dispose();
}
this._services.delete(identifier);
const name = typeof identifier === 'symbol' ? identifier.description : identifier.name;
logger.debug(`Unregistered service: ${name}`);
return true;
}
/**
*
*/
public clear(): void {
// 清理所有单例实例
for (const [, registration] of this._services) {
if (registration.instance) {
registration.instance.dispose();
}
}
this._services.clear();
2025-10-10 21:52:43 +08:00
this._updatableServices = [];
logger.debug('Cleared all services');
}
/**
*
*
* @returns
*/
public getRegisteredServices(): ServiceIdentifier[] {
return Array.from(this._services.keys());
}
2025-10-10 21:52:43 +08:00
/**
* 使@Updatable装饰器标记的服务
*
* update方法
* @Updatable装饰器验证过必须实现IUpdatable接口
* Core的主更新循环中调用
*
* @param deltaTime -
*
* @example
* ```typescript
* // 在Core的update方法中
* this._serviceContainer.updateAll(deltaTime);
* ```
*/
public updateAll(deltaTime?: number): void {
for (const { instance } of this._updatableServices) {
(instance as IService & { update: (deltaTime?: number) => void }).update(deltaTime);
2025-10-10 21:52:43 +08:00
}
}
/**
*
*
* @returns
*/
public getUpdatableCount(): number {
return this._updatableServices.length;
}
/**
*
*
* @returns
*/
public getAll(): IService[] {
const instances: IService[] = [];
for (const descriptor of this._services.values()) {
if (descriptor.instance) {
instances.push(descriptor.instance);
}
}
return instances;
}
}