This commit is contained in:
2025-10-11 12:05:57 +08:00
parent 45ec0fd021
commit 8d25c143c5
7 changed files with 437 additions and 0 deletions

View File

@@ -19,6 +19,7 @@
"lit": "^3.3.1",
"lodash": "^4.17.21",
"pinia": "^3.0.3",
"reflect-metadata": "^0.2.2",
"uuid": "^11.1.0",
"vue": "^3.5.18"
},

8
pnpm-lock.yaml generated
View File

@@ -20,6 +20,9 @@ importers:
pinia:
specifier: ^3.0.3
version: 3.0.3(typescript@5.8.3)(vue@3.5.18(typescript@5.8.3))
reflect-metadata:
specifier: ^0.2.2
version: 0.2.2
uuid:
specifier: ^11.1.0
version: 11.1.0
@@ -1368,6 +1371,9 @@ packages:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
reflect-metadata@0.2.2:
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
@@ -2902,6 +2908,8 @@ snapshots:
readdirp@4.1.2: {}
reflect-metadata@0.2.2: {}
rfdc@1.4.1: {}
rollup@4.46.2:

View File

@@ -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
}

View 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)
}
}

View 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
}))
}

View File

@@ -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

View File

@@ -13,6 +13,7 @@
"module": "ESNext",
"strict": true, // 严格模式检查
"experimentalDecorators": true, // 装饰器
"emitDecoratorMetadata": true, // 元数据反射
"useDefineForClassFields": false,
"strictPropertyInitialization": false, // 严格属性初始化检查
"noUnusedLocals": false, // 检查未使用的局部变量