/**
* @file 模块注册器
* @description 管理功能模块的注册、依赖解析和初始化
* @author JunBin.Yang
*/
import { Container, CoreServiceKeys, getContainer } from '@core/di';
import { NavigationService } from '@core/navigation';
import { FeatureModule, ModuleContext, RouteRegistry, DefaultRouteRegistry } from './FeatureModule';
import { Logger } from '@core/util';
const TAG: string = 'ModuleRegistry';
/**
* 模块状态
*/
export enum ModuleState {
/**
* 已注册,未初始化
*/
REGISTERED = 'registered',
/**
* 正在初始化
*/
INITIALIZING = 'initializing',
/**
* 已初始化
*/
INITIALIZED = 'initialized',
/**
* 初始化失败
*/
FAILED = 'failed'
}
/**
* 模块信息
*/
interface ModuleInfo {
module: FeatureModule;
state: ModuleState;
error?: Error;
}
/**
* 模块注册器配置
*/
export interface ModuleRegistryConfig {
/**
* DI 容器
*/
container?: Container;
/**
* 路由注册器
*/
routeRegistry?: RouteRegistry;
/**
* 是否启用日志
*/
enableLog?: boolean;
}
/**
* 模块注册器
* 负责管理所有功能模块的生命周期
*/
export class ModuleRegistry {
/**
* 已注册的模块
*/
private modules: Map<string, ModuleInfo> = new Map();
/**
* DI 容器
*/
private container: Container;
/**
* 路由注册器
*/
private routeRegistry: RouteRegistry;
/**
* 是否启用日志
*/
private enableLog: boolean;
/**
* 是否已启动
*/
private bootstrapped: boolean = false;
/**
* 构造函数
* @param config 配置选项
*/
constructor(config?: ModuleRegistryConfig) {
this.container = config?.container ?? getContainer();
this.routeRegistry = config?.routeRegistry ?? new DefaultRouteRegistry();
this.enableLog = config?.enableLog !== false;
}
/**
* 注册模块
* @param module 功能模块
*/
register(module: FeatureModule): void {
if (this.modules.has(module.moduleId)) {
this.log(`Module already registered: ${module.moduleId}`);
return;
}
this.modules.set(module.moduleId, {
module,
state: ModuleState.REGISTERED
});
this.log(`Module registered: ${module.moduleId}`);
}
/**
* 批量注册模块
* @param modules 功能模块数组
*/
registerAll(modules: FeatureModule[]): void {
for (const module of modules) {
this.register(module);
}
}
/**
* 启动所有模块
* 按依赖顺序初始化
*/
async bootstrap(): Promise<void> {
if (this.bootstrapped) {
this.log('Modules already bootstrapped');
return;
}
this.log('Starting module bootstrap...');
// 获取拓扑排序后的模块列表
const sortedModules = this.topologicalSort();
// 依次初始化模块
for (const moduleId of sortedModules) {
await this.initializeModule(moduleId);
}
this.bootstrapped = true;
this.log('Module bootstrap completed');
}
/**
* 初始化单个模块
* @param moduleId 模块 ID
*/
private async initializeModule(moduleId: string): Promise<void> {
const info = this.modules.get(moduleId);
if (!info) {
throw new Error(`Module not found: ${moduleId}`);
}
if (info.state === ModuleState.INITIALIZED) {
return;
}
if (info.state === ModuleState.INITIALIZING) {
throw new Error(`Circular dependency detected: ${moduleId}`);
}
info.state = ModuleState.INITIALIZING;
this.log(`Initializing module: ${moduleId}`);
try {
const module = info.module;
// 1. 注册服务
if (module.registerServices) {
module.registerServices(this.container);
this.log(` - Services registered for: ${moduleId}`);
}
// 2. 注册路由
if (module.registerRoutes) {
module.registerRoutes(this.routeRegistry);
this.log(` - Routes registered for: ${moduleId}`);
}
// 3. 注册守卫
const navigationService = this.container.tryResolve<NavigationService>(CoreServiceKeys.NavigationService);
if (module.registerGuards && navigationService) {
module.registerGuards(navigationService);
this.log(` - Guards registered for: ${moduleId}`);
}
// 4. 调用初始化钩子
if (module.onInit) {
const context: ModuleContext = {
container: this.container,
routeRegistry: this.routeRegistry,
navigationService: navigationService
};
await module.onInit(context);
this.log(` - onInit completed for: ${moduleId}`);
}
info.state = ModuleState.INITIALIZED;
this.log(`Module initialized: ${moduleId}`);
} catch (error) {
info.state = ModuleState.FAILED;
info.error = error instanceof Error ? error : new Error(String(error));
this.logError(`Module initialization failed: ${moduleId}, error: ${info.error.message}`);
throw info.error;
}
}
/**
* 拓扑排序
* 按依赖关系排序模块
* @returns 排序后的模块 ID 列表
*/
private topologicalSort(): string[] {
const result: string[] = [];
const visited = new Set<string>();
const visiting = new Set<string>();
const visit = (moduleId: string) => {
if (visited.has(moduleId)) {
return;
}
if (visiting.has(moduleId)) {
throw new Error(`Circular dependency detected: ${moduleId}`);
}
visiting.add(moduleId);
const info = this.modules.get(moduleId);
if (info?.module.dependencies) {
for (const dep of info.module.dependencies) {
if (this.modules.has(dep)) {
visit(dep);
} else {
this.log(`Warning: Dependency not found: ${dep} (required by ${moduleId})`);
}
}
}
visiting.delete(moduleId);
visited.add(moduleId);
result.push(moduleId);
};
for (const moduleId of this.modules.keys()) {
visit(moduleId);
}
return result;
}
/**
* 获取模块状态
* @param moduleId 模块 ID
* @returns 模块状态
*/
getModuleState(moduleId: string): ModuleState | undefined {
return this.modules.get(moduleId)?.state;
}
/**
* 获取所有已注册的模块 ID
* @returns 模块 ID 列表
*/
getModuleIds(): string[] {
return Array.from(this.modules.keys());
}
/**
* 获取模块数量
* @returns 模块数量
*/
get size(): number {
return this.modules.size;
}
/**
* 检查是否已启动
* @returns 是否已启动
*/
isBootstrapped(): boolean {
return this.bootstrapped;
}
/**
* 销毁所有模块
*/
destroy(): void {
for (const entry of this.modules.entries()) {
const moduleId = entry[0];
const info = entry[1];
if (info.module.onDestroy) {
try {
info.module.onDestroy();
this.log(`Module destroyed: ${moduleId}`);
} catch (error) {
this.logError(`Module destroy failed: ${moduleId}`);
}
}
}
this.modules.clear();
this.bootstrapped = false;
this.log('All modules destroyed');
}
/**
* 记录日志
*/
private log(message: string): void {
if (this.enableLog) {
Logger.info(message, TAG);
}
}
/**
* 记录错误日志
*/
private logError(message: string): void {
Logger.error(message, TAG);
}
}