111
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { ServiceRegistry, ServiceIds } from './ServiceRegistry'
|
||||
import type { IServiceContainer } from './IServiceContainer'
|
||||
import { initializePendingServices } from './decorators'
|
||||
|
||||
/**
|
||||
* 服务提供者
|
||||
@@ -23,6 +24,9 @@ export class ServiceProvider {
|
||||
|
||||
this.container = registry.getContainer()
|
||||
this.container.initialize()
|
||||
|
||||
// 初始化所有使用@Service装饰器的服务
|
||||
initializePendingServices()
|
||||
|
||||
this.initialized = true
|
||||
}
|
||||
|
||||
206
src/services/di/decorator-example.ts
Normal file
206
src/services/di/decorator-example.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* 装饰器式依赖注入示例
|
||||
* 展示如何使用@Service和@Inject装饰器实现类似Java的自动依赖注入
|
||||
*/
|
||||
|
||||
import { Service, Inject } from './decorators'
|
||||
import { ServiceIds } from './ServiceRegistry'
|
||||
|
||||
// 示例1: 基本的服务定义和注入
|
||||
|
||||
/**
|
||||
* 用户服务接口
|
||||
*/
|
||||
interface IUserService {
|
||||
getUserName(): string
|
||||
setUserName(name: string): void
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户服务实现
|
||||
* 使用@Service装饰器标记为可注入服务
|
||||
*/
|
||||
@Service() // 自动使用类名"UserService"作为服务ID
|
||||
export class UserService implements IUserService {
|
||||
private userName = 'Default User'
|
||||
|
||||
getUserName(): string {
|
||||
return this.userName
|
||||
}
|
||||
|
||||
setUserName(name: string): void {
|
||||
this.userName = name
|
||||
}
|
||||
}
|
||||
|
||||
// 示例2: 带自定义ID和依赖的服务
|
||||
|
||||
/**
|
||||
* 日志服务
|
||||
*/
|
||||
@Service({
|
||||
id: 'customLoggerService', // 自定义服务ID
|
||||
dependencies: [] // 无依赖
|
||||
})
|
||||
export class LoggerService {
|
||||
log(message: string): void {
|
||||
console.log(`[Logger] ${new Date().toISOString()}: ${message}`)
|
||||
}
|
||||
|
||||
error(message: string, error?: Error): void {
|
||||
console.error(`[Logger] ERROR ${new Date().toISOString()}: ${message}`, error)
|
||||
}
|
||||
}
|
||||
|
||||
// 示例3: 具有依赖的服务
|
||||
|
||||
/**
|
||||
* 认证服务
|
||||
* 依赖于UserService和LoggerService
|
||||
*/
|
||||
@Service({
|
||||
dependencies: [UserService, 'customLoggerService'] // 可以混合使用类和服务ID
|
||||
})
|
||||
export class AuthService {
|
||||
// 按类型自动注入
|
||||
@Inject()
|
||||
private userService!: UserService
|
||||
|
||||
// 按服务ID注入
|
||||
@Inject('customLoggerService')
|
||||
private logger!: LoggerService
|
||||
|
||||
// 注入系统内置服务(使用ServiceIds)
|
||||
@Inject(ServiceIds.EVENT_BUILDER)
|
||||
private eventBuilder!: any
|
||||
|
||||
authenticate(userName: string): boolean {
|
||||
this.logger.log(`尝试认证用户: ${userName}`)
|
||||
|
||||
if (userName) {
|
||||
this.userService.setUserName(userName)
|
||||
this.logger.log(`认证成功: ${userName}`)
|
||||
|
||||
// 使用事件构建器发送认证成功事件
|
||||
if (this.eventBuilder) {
|
||||
try {
|
||||
this.eventBuilder.build('auth.success', { userName })
|
||||
} catch (error) {
|
||||
this.logger.error('发送认证事件失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
this.logger.error('认证失败: 用户名不能为空')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 示例4: 在组件或业务类中使用
|
||||
|
||||
/**
|
||||
* 用户控制器
|
||||
* 展示如何在业务类中使用注入的服务
|
||||
*/
|
||||
export class UserController {
|
||||
// 按类型自动注入
|
||||
@Inject()
|
||||
private authService!: AuthService
|
||||
|
||||
// 按类型自动注入
|
||||
@Inject()
|
||||
private userService!: UserService
|
||||
|
||||
login(userName: string): boolean {
|
||||
if (this.authService.authenticate(userName)) {
|
||||
console.log(`用户控制器: ${this.userService.getUserName()} 已登录`)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 示例5: 复杂的依赖链
|
||||
|
||||
/**
|
||||
* 数据访问服务
|
||||
*/
|
||||
@Service()
|
||||
export class DataAccessService {
|
||||
save(data: any): void {
|
||||
console.log('保存数据:', data)
|
||||
}
|
||||
|
||||
get(id: string): any {
|
||||
console.log(`获取数据ID: ${id}`)
|
||||
return { id, name: '示例数据' }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户管理服务
|
||||
* 依赖于DataAccessService、UserService和LoggerService
|
||||
*/
|
||||
@Service({
|
||||
dependencies: [DataAccessService, UserService, LoggerService]
|
||||
})
|
||||
export class UserManagementService {
|
||||
@Inject()
|
||||
private dataAccessService!: DataAccessService
|
||||
|
||||
@Inject()
|
||||
private userService!: UserService
|
||||
|
||||
@Inject()
|
||||
private loggerService!: LoggerService
|
||||
|
||||
updateUserProfile(userId: string, profile: any): boolean {
|
||||
try {
|
||||
this.loggerService.log(`更新用户${userId}的资料`)
|
||||
const currentUser = this.userService.getUserName()
|
||||
|
||||
const userData = {
|
||||
...profile,
|
||||
userId,
|
||||
updatedBy: currentUser,
|
||||
updatedAt: new Date()
|
||||
}
|
||||
|
||||
this.dataAccessService.save(userData)
|
||||
this.loggerService.log(`用户${userId}资料更新成功`)
|
||||
return true
|
||||
} catch (error) {
|
||||
this.loggerService.error('更新用户资料失败', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行示例
|
||||
* 注意:此函数需要在ServiceProvider初始化后调用
|
||||
*/
|
||||
export async function runDecoratorExample(): Promise<void> {
|
||||
try {
|
||||
console.log('\n=== 开始运行装饰器式DI示例 ===')
|
||||
|
||||
// 创建控制器实例
|
||||
const userController = new UserController()
|
||||
|
||||
// 测试登录功能
|
||||
userController.login('张三')
|
||||
|
||||
// 测试用户管理服务
|
||||
const userManagementService = new UserManagementService()
|
||||
userManagementService.updateUserProfile('user123', {
|
||||
displayName: '张三',
|
||||
email: 'zhangsan@example.com'
|
||||
})
|
||||
|
||||
console.log('=== 装饰器式DI示例运行完成 ===\n')
|
||||
} catch (error) {
|
||||
console.error('示例运行失败:', error)
|
||||
}
|
||||
}
|
||||
203
src/services/di/decorators.ts
Normal file
203
src/services/di/decorators.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* 依赖注入装饰器
|
||||
* 提供类似Java的自动注入功能
|
||||
*/
|
||||
|
||||
import { ServiceProvider } from './ServiceProvider'
|
||||
import { ServiceRegistry } from './ServiceRegistry'
|
||||
import 'reflect-metadata';
|
||||
|
||||
// 定义构造函数类型
|
||||
type Constructor<T = any> = new (...args: any[]) => T
|
||||
|
||||
// 存储类到服务ID的映射
|
||||
const classToServiceIdMap = new Map<Constructor, string>()
|
||||
// 存储服务ID到类的映射
|
||||
const serviceIdToClassMap = new Map<string, Constructor>()
|
||||
// 存储需要延迟注册的服务
|
||||
const pendingServices: Array<{
|
||||
serviceClass: Constructor
|
||||
serviceId: string
|
||||
dependencies: Array<string | Constructor>
|
||||
}> = []
|
||||
|
||||
/**
|
||||
* 服务装饰器
|
||||
* 用于标记一个类作为可注入的服务
|
||||
* @param options 服务配置选项
|
||||
*/
|
||||
export function Service(options?: {
|
||||
/** 自定义服务ID,如果不提供则使用类名 */
|
||||
id?: string
|
||||
/** 服务依赖,可以是服务ID字符串或依赖类 */
|
||||
dependencies?: Array<string | Constructor>
|
||||
/** 是否为单例模式,默认为true */
|
||||
singleton?: boolean
|
||||
}): ClassDecorator {
|
||||
return (target: Function) => {
|
||||
// 断言target为Constructor类型
|
||||
const serviceClass = target as Constructor
|
||||
const serviceId = options?.id || target.name
|
||||
const dependencies = options?.dependencies || []
|
||||
|
||||
// 保存映射关系
|
||||
classToServiceIdMap.set(serviceClass, serviceId)
|
||||
serviceIdToClassMap.set(serviceId, serviceClass)
|
||||
|
||||
// 将服务添加到待注册列表
|
||||
pendingServices.push({
|
||||
serviceClass,
|
||||
serviceId,
|
||||
dependencies
|
||||
})
|
||||
|
||||
// 尝试注册服务
|
||||
tryRegisterPendingServices()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入装饰器
|
||||
* 用于自动注入服务实例
|
||||
* @param dependency 依赖的服务类或服务ID
|
||||
*/
|
||||
export function Inject(dependency?: Function | string): PropertyDecorator {
|
||||
return (target: Object, propertyKey: string | symbol) => {
|
||||
// 获取属性的类型(如果使用了TypeScript)
|
||||
const propertyType = Reflect.getMetadata('design:type', target, propertyKey)
|
||||
|
||||
const descriptor = {
|
||||
get: () => {
|
||||
try {
|
||||
let serviceId: string
|
||||
|
||||
if (typeof dependency === 'string') {
|
||||
// 直接使用提供的服务ID
|
||||
serviceId = dependency
|
||||
} else if (dependency) {
|
||||
// 使用提供的类获取服务ID
|
||||
serviceId = getServiceIdForClass(dependency)
|
||||
} else if (propertyType) {
|
||||
// 使用属性类型获取服务ID
|
||||
serviceId = getServiceIdForClass(propertyType)
|
||||
} else {
|
||||
throw new Error(`无法确定属性 ${String(propertyKey)} 的注入类型`)
|
||||
}
|
||||
|
||||
return ServiceProvider.getService(serviceId)
|
||||
} catch (error) {
|
||||
console.error(`注入服务失败: ${String(propertyKey)}`, error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(target, propertyKey, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类对应的服务ID
|
||||
* @param cls 服务类
|
||||
*/
|
||||
function getServiceIdForClass(cls: Function): string {
|
||||
const serviceId = classToServiceIdMap.get(cls)
|
||||
if (!serviceId) {
|
||||
throw new Error(`类 ${cls.name} 未注册为服务`)
|
||||
}
|
||||
return serviceId
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试注册所有待注册的服务
|
||||
*/
|
||||
function tryRegisterPendingServices(): void {
|
||||
if (pendingServices.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const registry = ServiceRegistry.getInstance()
|
||||
const container = registry.getContainer()
|
||||
|
||||
// 处理所有待注册的服务
|
||||
for (const pendingService of pendingServices.slice()) {
|
||||
// 解析依赖的服务ID
|
||||
const resolvedDependencies: string[] = []
|
||||
for (const dep of pendingService.dependencies) {
|
||||
if (typeof dep === 'string') {
|
||||
resolvedDependencies.push(dep)
|
||||
} else if (typeof dep === 'function') {
|
||||
const depServiceId = classToServiceIdMap.get(dep)
|
||||
if (depServiceId) {
|
||||
resolvedDependencies.push(depServiceId)
|
||||
} else {
|
||||
// 依赖尚未注册,跳过当前服务
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查所有依赖是否都已注册
|
||||
const allDependenciesRegistered = resolvedDependencies.every(depId =>
|
||||
container.has(depId)
|
||||
)
|
||||
|
||||
if (allDependenciesRegistered) {
|
||||
// 注册服务
|
||||
container.register(
|
||||
pendingService.serviceId,
|
||||
(container) => {
|
||||
// 创建服务实例
|
||||
const ServiceClass = pendingService.serviceClass
|
||||
// 使用依赖注入创建实例
|
||||
const instance = new ServiceClass()
|
||||
return instance
|
||||
},
|
||||
resolvedDependencies
|
||||
)
|
||||
|
||||
// 从待注册列表中移除
|
||||
const index = pendingServices.indexOf(pendingService)
|
||||
if (index > -1) {
|
||||
pendingServices.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// 服务注册表可能尚未初始化,稍后再试
|
||||
console.debug('服务注册暂时失败,将在初始化时重试:')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化所有待注册的服务
|
||||
* 在ServiceProvider初始化后调用
|
||||
*/
|
||||
export function initializePendingServices(): void {
|
||||
// 重试注册所有剩余的服务
|
||||
while (pendingServices.length > 0) {
|
||||
const beforeCount = pendingServices.length
|
||||
tryRegisterPendingServices()
|
||||
|
||||
// 如果没有服务被注册,可能存在循环依赖,跳出循环
|
||||
if (beforeCount === pendingServices.length) {
|
||||
console.warn('以下服务无法注册,可能存在循环依赖:',
|
||||
pendingServices.map(s => s.serviceId).join(', '))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有已注册的服务信息
|
||||
*/
|
||||
export function getRegisteredServices(): Array<{
|
||||
serviceId: string
|
||||
serviceClass: Function
|
||||
}> {
|
||||
return Array.from(classToServiceIdMap.entries()).map(([cls, id]) => ({
|
||||
serviceId: id,
|
||||
serviceClass: cls
|
||||
}))
|
||||
}
|
||||
14
src/services/di/types.d.ts
vendored
14
src/services/di/types.d.ts
vendored
@@ -89,3 +89,17 @@ declare module './ServiceProvider' {
|
||||
* 声明Inject装饰器类型
|
||||
*/
|
||||
declare function Inject<T extends keyof ServiceTypeMap>(serviceId: T): PropertyDecorator
|
||||
|
||||
/**
|
||||
* 声明新的Inject装饰器类型,支持类注入
|
||||
*/
|
||||
declare function Inject<T>(dependency?: Function | string): PropertyDecorator
|
||||
|
||||
/**
|
||||
* 声明Service装饰器类型
|
||||
*/
|
||||
declare function Service(options?: {
|
||||
id?: string
|
||||
dependencies?: Array<string | Function>
|
||||
singleton?: boolean
|
||||
}): ClassDecorator
|
||||
|
||||
Reference in New Issue
Block a user