expo-popcore-app/.claude/skills/repo-core-di/SKILL.md

8.3 KiB
Raw Permalink Blame History

name description
repo-core-di @repo/core 依赖注入框架使用指南。当需要创建注入器、注册提供者、使用装饰器(@Injectable, @Inject, @Optional等)、处理生命周期(OnInit, OnDestroy)、或解决循环依赖时使用此技能。适用于:(1) 创建和配置注入器层次结构 (2) 注册各类提供者(Value/Class/Factory/Lazy) (3) 使用参数装饰器控制注入行为 (4) 实现服务生命周期管理 (5) 使用 InjectionToken 和 ForwardRef

@repo/core 依赖注入框架

核心概念

@repo/core 提供企业级依赖注入框架,支持层次化注入器、多种提供者类型、生命周期管理。

注入器层次结构

Root (根注入器)
  └── Platform (平台注入器)
        └── Application (应用注入器)
              └── Feature (特性注入器)

快速开始

创建注入器

import { EnvironmentInjector, Injectable, InjectionToken } from '@repo/core'

// 定义类型安全的令牌
const API_URL = new InjectionToken<string>('API_URL')

// 创建根注入器
const rootInjector = EnvironmentInjector.createRootInjector([
  { provide: API_URL, useValue: 'https://api.example.com' }
])

// 创建应用注入器(继承根注入器)
const appInjector = EnvironmentInjector.createApplicationInjector([
  UserService,
  { provide: LoggerService, useClass: LoggerService }
])

// 初始化(执行所有 @OnInit
await appInjector.init()

// 获取服务
const userService = appInjector.get(UserService)

使用 @Injectable 装饰器

import { Injectable } from '@repo/core'

// providedIn: 'root' - 单例,自动注册到根注入器
@Injectable({ providedIn: 'root' })
class ConfigService {
  apiUrl = 'https://api.example.com'
}

// providedIn: 'auto' - 不自动注册到根注入器,可在任何注入器中被按需解析
// 推荐用于请求级服务
@Injectable({ providedIn: 'auto' })
class RequestScopedService {
  // 每次请求创建新实例
}

// 使用工厂函数
@Injectable({
  providedIn: 'root',
  useFactory: (config: ConfigService) => new ApiClient(config.apiUrl),
  deps: [ConfigService]
})
class ApiClient {
  constructor(public baseUrl: string) {}
}

提供者类型

值提供者 (ValueProvider)

const API_URL = new InjectionToken<string>('API_URL')
const CONFIG_TOKEN = new InjectionToken<AppConfig>('CONFIG_TOKEN')

{ provide: API_URL, useValue: 'https://api.example.com' }
{ provide: CONFIG_TOKEN, useValue: { debug: true, timeout: 5000 } }

类提供者 (ClassProvider)

{ provide: UserService, useClass: UserService }
{ provide: Logger, useClass: ConsoleLogger }  // 接口映射到实现

工厂提供者 (FactoryProvider)

{
  provide: DatabaseConnection,
  useFactory: (config: ConfigService) => {
    return new DatabaseConnection(config.dbUrl)
  },
  deps: [ConfigService]
}

别名提供者 (ExistingProvider)

const LOGGER_TOKEN = new InjectionToken<Logger>('Logger')

{ provide: LOGGER_TOKEN, useExisting: LoggerService }

延迟提供者 (LazyProvider)

const LAZY_CONFIG = new InjectionToken<AppConfig>('LAZY_CONFIG')

// 延迟类 - 首次访问时才实例化
{ provide: HeavyService, useLazyClass: HeavyService }

// 延迟工厂
{ provide: LAZY_CONFIG, useLazyFactory: () => loadConfig(), deps: [] }

多值提供者 (Multi Provider)

{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }

// 获取时返回数组
const interceptors = injector.get(HTTP_INTERCEPTORS) // [AuthInterceptor, LoggingInterceptor]

参数装饰器

@Inject - 显式指定注入令牌

const API_URL = new InjectionToken<string>('API_URL')

class UserController {
  constructor(
    @Inject(UserService) private userService: UserService,
    @Inject(API_URL) private apiUrl: string
  ) {}
}

@Optional - 可选注入

class NotificationService {
  constructor(
    @Optional(EmailService) private email?: EmailService  // 不存在时为 null
  ) {}
}

@Self - 仅在当前注入器查找

class ChildComponent {
  constructor(
    @Self(LocalService) private local: LocalService  // 不查找父注入器
  ) {}
}

@SkipSelf - 跳过当前注入器

class ChildService {
  constructor(
    @SkipSelf(ParentService) private parent: ParentService  // 从父注入器开始查找
  ) {}
}

@Host - 在宿主注入器查找

class DirectiveService {
  constructor(
    @Host(HostService) private host: HostService
  ) {}
}

生命周期管理

@OnInit 装饰器

import { Injectable, OnInit } from '@repo/core'

@Injectable({ providedIn: 'root' })
class DatabaseService implements OnInit {
  private connection: Connection

  @OnInit()
  async onInit() {
    this.connection = await this.connect()
    console.log('Database connected')
  }

  private async connect() {
    // 连接逻辑
  }
}

OnDestroy 接口

import { Injectable, OnDestroy } from '@repo/core'

@Injectable({ providedIn: 'root' })
class CacheService implements OnDestroy {
  async onDestroy() {
    await this.flush()
    console.log('Cache flushed')
  }
}

// 销毁注入器时自动调用
await injector.destroy()

APP_INITIALIZER - 应用初始化器

import { APP_INITIALIZER, InjectionToken } from '@repo/core'

const appInjector = EnvironmentInjector.createApplicationInjector([
  {
    provide: APP_INITIALIZER,
    useValue: {
      provide: new InjectionToken('DB_INIT'),
      deps: [ConfigService],
      init: async () => {
        await initDatabase()
      }
    },
    multi: true
  },
  {
    provide: APP_INITIALIZER,
    useValue: {
      provide: new InjectionToken('CACHE_INIT'),
      deps: [new InjectionToken('DB_INIT')],  // 依赖 DB_INIT
      init: async () => {
        await initCache()
      }
    },
    multi: true
  }
])

// 按依赖顺序执行初始化器
await appInjector.init()

InjectionToken

import { InjectionToken } from '@repo/core'

// 创建类型安全的令牌
const API_URL = new InjectionToken<string>('API_URL')
const CONFIG = new InjectionToken<AppConfig>('CONFIG')
const LOGGER_LEVEL = new InjectionToken<LoggerLevel>('LOGGER_LEVEL')

// 注册
const injector = EnvironmentInjector.createRootInjector([
  { provide: API_URL, useValue: 'https://api.example.com' },
  { provide: CONFIG, useValue: { debug: true } }
])

// 获取(类型安全)
const url: string = injector.get(API_URL)
const config: AppConfig = injector.get(CONFIG)

ForwardRef - 解决循环依赖

import { Injectable, Inject, forwardRef } from '@repo/core'

@Injectable({ providedIn: 'root' })
class ServiceA {
  constructor(
    @Inject(forwardRef(() => ServiceB)) private serviceB: ServiceB
  ) {}
}

@Injectable({ providedIn: 'root' })
class ServiceB {
  constructor(
    @Inject(forwardRef(() => ServiceA)) private serviceA: ServiceA
  ) {}
}

便捷工厂函数

import {
  createRootInjector,
  createPlatformInjector,
  createApplicationInjector,
  createFeatureInjector
} from '@repo/core'

// 简化创建
const root = createRootInjector([...providers])
const platform = createPlatformInjector([...providers])
const app = createApplicationInjector([...providers])
const feature = createFeatureInjector([...providers], parentInjector)

最佳实践

  1. 使用 providedIn: 'root' - 大多数服务应该是单例
  2. 避免循环依赖 - 使用 ForwardRef 仅作为最后手段
  3. 使用 InjectionToken - 为非类类型创建类型安全令牌
  4. 实现 OnDestroy - 清理资源(连接、订阅等)
  5. 使用 APP_INITIALIZER - 管理复杂的初始化顺序
  6. 延迟加载 - 对重型服务使用 useLazyClass/useLazyFactory

参考文档