跳转至

Symphra Container 完整 API 设计文档

1. 类型系统设计

1.1 核心类型定义

# src/symphra_container/types.py

from typing import TypeVar, Generic, Protocol, Union, Optional, Callable, Any, Dict, Type
from typing_extensions import TypedDict, Literal, overload
from enum import Enum

# ============ 基础类型 ============

T = TypeVar("T")
T_co = TypeVar("T_co", covariant=True)
ServiceKey = Union[Type[T], str]

class Lifetime(str, Enum):
    """服务生命周期枚举"""
    SINGLETON = "singleton"      # 全局唯一
    TRANSIENT = "transient"      # 每次创建新实例
    SCOPED = "scoped"            # 作用域内共享
    FACTORY = "factory"          # 工厂模式

class ProviderType(str, Enum):
    """提供者类型"""
    CLASS = "class"              # 类构造函数
    FACTORY = "factory"          # 工厂函数
    INSTANCE = "instance"        # 直接实例
    VALUE = "value"              # 配置值

# ============ 服务描述符 ============

class ServiceDescriptor(Generic[T]):
    """服务描述符 - 存储服务的完整注册信息"""
    service_type: Type[T] | str
    impl_type: Optional[Type[T]]
    factory: Optional[Callable[..., T]]
    instance: Optional[T]
    lifetime: Lifetime
    provider_type: ProviderType
    is_singleton: bool
    metadata: Dict[str, Any]

# ============ 错误类型 ============

class ServiceNotFoundError(Exception):
    """服务未找到异常"""
    pass

class CircularDependencyError(Exception):
    """循环依赖异常"""
    pass

class InvalidServiceError(Exception):
    """无效的服务定义"""
    pass

class RegistrationError(Exception):
    """注册错误"""
    pass

# ============ 协议定义 ============

class Provider(Protocol[T_co]):
    """服务提供者协议"""
    def provide(self) -> T_co: ...

class Resolver(Protocol):
    """依赖解析器协议"""
    def resolve(self, service_type: Type[T], container: "Container") -> T: ...

class LifetimeManager(Protocol):
    """生命周期管理器协议"""
    def get_instance(self, factory: Callable) -> Any: ...
    def dispose(self) -> None: ...

1.2 字符串键类型提示方案

# src/symphra_container/registry.py

from typing_extensions import TypedDict, Literal, overload

class ServiceRegistry(TypedDict, total=False):
    """
    服务注册表类型定义 - 用于IDE类型提示

    使用方式:
    registry: ServiceRegistry = {
        "database": DatabaseImpl(),
        "cache": CacheImpl(),
        "logger": LoggerImpl(),
    }

    # IDE 会推断 registry["database"] 的类型
    """
    # 基础服务
    database: Any
    cache: Any
    logger: Any
    config: Any
    # ... 更多服务定义

    # 这样定义后,使用字符串键时 IDE 能提供自动补全

# ============ 更优雅的方案:使用 Literal + overload ============

@overload
def get(self, key: Literal["database"]) -> Database: ...

@overload
def get(self, key: Literal["cache"]) -> Cache: ...

@overload
def get(self, key: Literal["logger"]) -> Logger: ...

@overload
def get(self, key: str, service_type: Type[T]) -> T: ...

def get(self, key: str, service_type: Type[T] | None = None) -> T:
    """获取服务"""
    ...

# 使用示例
db = container.get("database")  # IDE 推断为 Database 类型
cache = container.get("cache")  # IDE 推断为 Cache 类型
logger = container.get("logger")  # IDE 推断为 Logger 类型

# 未知服务时需指定类型
service = container.get("custom_service", CustomService)

2. 完整 API 设计

2.1 容器初始化

from symphra_container import Container, Lifetime, inject

# ============ 初始化容器 ============

# 方式 1: 创建新容器
container = Container()

# 方式 2: 创建子容器(继承父容器配置)
child_container = container.create_child()

# 方式 3: 创建带名称的容器(便于调试)
container = Container(name="MyApp")

# 方式 4: 从配置文件创建
container = Container.from_config("config.yaml")

2.2 注册服务

2.2.1 基础注册(类型键)

# ============ 类型键注册 ============

# 注册 1: 自动装配(使用实现类本身)
container.register(UserService)
# 等价于: container.register(UserService, UserService)

# 注册 2: 指定实现类
class IUserService(Protocol):
    def get_user(self, id: int) -> User: ...

container.register(IUserService, UserService)

# 注册 3: 指定生命周期(默认 SINGLETON)
container.register(
    UserService,
    lifetime=Lifetime.TRANSIENT
)

# 注册 4: 带覆盖参数
container.register(
    IUserService,
    UserServiceV1,
    lifetime=Lifetime.SINGLETON,
    override=False  # 默认 False,忽略重复注册
)

# 更新为 V2(使用 override=True)
container.register(
    IUserService,
    UserServiceV2,
    override=True  # 覆盖之前的注册
)

# ============ 类型键获取 ============

# 获取 1: 基础解析
user_service = container.resolve(UserService)  # 返回 UserService 实例

# 获取 2: 解析接口(自动推断为实现类)
service = container.resolve(IUserService)  # 返回 UserService 实例

# 获取 3: 尝试解析(返回 Optional)
service = container.try_resolve(NonExistentService)  # 返回 None

2.2.2 字符串键注册

# ============ 字符串键注册 ============

# 注册 1: 类实现
container.register(
    "user_service",
    UserService,
    lifetime=Lifetime.SINGLETON
)

# 注册 2: 工厂函数
def create_database():
    return Database(
        host="localhost",
        port=5432
    )

container.register_factory(
    "database",
    create_database,
    lifetime=Lifetime.SINGLETON
)

# 注册 3: 直接实例
config = Config.from_file("config.yaml")
container.register_instance("config", config)

# 注册 4: 配置值
container.register_value("api_key", "sk_live_xxxxx")
container.register_value("max_connections", 100)
container.register_value("debug_mode", True)

# ============ 字符串键获取 ============

# 获取 1: 基础获取(需要类型注解辅助)
db: Database = container.get("database")  # IDE 推断为 Database

# 获取 2: 显式指定类型
db = container.get("database", Database)

# 获取 3: 获取配置值
api_key = container.get("api_key")  # 返回 str
max_conn = container.get("max_connections")  # 返回 int

# 获取 4: 尝试获取
db = container.try_get("optional_service")  # 返回 None if not found

2.2.3 工厂函数注册

# ============ 工厂函数(同步) ============

# 方式 1: 简单工厂
def create_logger():
    return Logger("myapp.log")

container.register_factory(
    "logger",
    create_logger,
    lifetime=Lifetime.SINGLETON
)

# 方式 2: 工厂依赖容器
def create_db_connection(container: Container):
    config = container.resolve(Config)
    return Database(**config.database)

container.register_factory(
    "db_conn",
    create_db_connection,
    lifetime=Lifetime.SINGLETON
)

# 方式 3: 工厂依赖其他服务
def create_user_service(db: Database, logger: Logger):
    return UserService(db, logger)

# 容器会自动解析 db 和 logger 参数
container.register_factory(
    "user_service",
    create_user_service,
    lifetime=Lifetime.TRANSIENT
)

# ============ 工厂函数(异步) ============

async def create_async_db():
    return await Database.connect("postgresql://...")

container.register_async_factory(
    "async_db",
    create_async_db,
    lifetime=Lifetime.SINGLETON
)

# 异步解析
db = await container.resolve_async("async_db")

2.2.4 高级注册模式

# ============ 条件注册 ============

# 根据配置条件注册
if config.use_postgres:
    container.register(IDatabase, PostgresDatabase)
else:
    container.register(IDatabase, SQLiteDatabase)

# ============ 批量注册 ============

# 同时注册多个实现为同一接口
implementations = [
    UserServiceImpl,
    OrderServiceImpl,
    PaymentServiceImpl,
]

for impl in implementations:
    # 使用模块名 + 类名作为 key
    key = f"{impl.__module__}.{impl.__name__}"
    container.register(key, impl)

# ============ 装饰器注册(自动扫描)============

@injectable(lifetime=Lifetime.SINGLETON)
class UserRepository:
    pass

@injectable.transient
class OrderService:
    pass

@injectable.factory
def create_cache():
    return Redis()

# 自动注册所有标记的类
container.scan("myapp.services")

# ============ 模块化注册 ============

class DatabaseModule(ContainerModule):
    def configure(self, container: Container):
        container.register("db", DatabaseImpl)
        container.register("connection_pool", ConnectionPool)

container.register_module(DatabaseModule())

2.3 获取服务

# ============ 类型键获取 ============

# 基础解析 - 推荐用于有类型的情况
service: UserService = container.resolve(UserService)

# 解析接口
service: IUserService = container.resolve(IUserService)

# 尝试解析 - 返回 Optional
service = container.try_resolve(UserService)  # Optional[UserService]

# ============ 字符串键获取 ============

# 方式 1: 带类型注解(推荐)
db: Database = container.get("database")

# 方式 2: 显式指定类型
db = container.get("database", Database)

# 方式 3: 尝试获取
db = container.try_get("database")  # Optional[Database]

# 方式 4: 获取所有注册的某类型服务
loggers = container.get_all(Logger)  # List[Logger]
loggers = container.get_all("logger*")  # 使用 glob 模式匹配

# ============ 获取服务信息 ============

# 检查服务是否已注册
exists = container.has("database")  # bool
exists = container.has(UserService)  # bool

# 获取服务元数据
descriptor = container.get_descriptor(UserService)
print(descriptor.lifetime)  # Lifetime.SINGLETON
print(descriptor.lifetime_manager)  # SingletonManager instance

# ============ 异步获取 ============

# 异步解析服务
db = await container.resolve_async(Database)

# 异步获取字符串键
service = await container.get_async("async_service")

2.4 删除和覆盖

# ============ 删除服务 ============

# 删除 1: 按类型删除
container.unregister(UserService)

# 删除 2: 按字符串键删除
container.unregister("database")

# 删除 3: 删除所有实现某接口的服务
container.unregister(IUserService, all=True)

# 删除 4: 安全删除(不存在也不报错)
container.try_unregister("optional_service")

# ============ 清空容器 ============

# 清空所有服务(谨慎使用)
container.clear()

# 清空特定生命周期的服务
container.clear(lifetime=Lifetime.TRANSIENT)

# ============ 覆盖服务 ============

# 方式 1: 使用 override 参数(注册时)
container.register(UserService, NewUserService, override=True)

# 方式 2: 先删除后注册
container.unregister(UserService)
container.register(UserService, NewUserService)

# 方式 3: 直接替换(新增方法)
container.replace(UserService, NewUserService)

2.5 作用域管理

# ============ 创建作用域 ============

# 方式 1: Context Manager(推荐)
with container.create_scope() as scope:
    service = scope.resolve(UserService)
    # 在作用域内,Scoped 生命周期的服务共享实例
    # 作用域结束时自动清理资源

# 方式 2: 手动管理
scope = container.create_scope()
try:
    service = scope.resolve(UserService)
finally:
    scope.dispose()

# ============ 异步作用域 ============

async with container.create_async_scope() as scope:
    service = await scope.resolve_async(UserService)

# ============ 作用域特性 ============

# 继承父容器的 Singleton 和 Transient
# 为 Scoped 生命周期的服务提供隔离环境

with container.create_scope() as scope1:
    user_service1 = scope1.resolve(UserService)  # Scoped

with container.create_scope() as scope2:
    user_service2 = scope2.resolve(UserService)  # 不同实例

# Singleton 在全局共享
db = container.resolve(Database)  # 全局单例

2.6 依赖注入(构造函数)

# ============ 自动装配(构造函数) ============

class UserRepository:
    def __init__(self, db: Database):  # 类型注解
        self.db = db

class UserService:
    def __init__(self, repo: UserRepository, logger: Logger):
        self.repo = repo
        self.logger = logger

# 注册
container.register(Database, PostgresDatabase)
container.register(UserRepository)
container.register(UserService)

# 自动解析完整依赖链
service = container.resolve(UserService)
# 容器自动解析:UserService -> UserRepository -> Database

# ============ 可选依赖(有默认值) ============

class ConfigService:
    def __init__(
        self,
        db: Database,  # 必须从容器解析
        timeout: int = 30,  # 优先容器解析,无则用默认值
        max_retries: int = 3
    ):
        self.db = db
        self.timeout = timeout
        self.max_retries = max_retries

# 使用方式
container.register(Database, PostgresDatabase)
container.register("timeout", 60)  # 可选:覆盖默认值

service = container.resolve(ConfigService)
# service.db -> Database 实例
# service.timeout -> 60(来自容器)或 30(默认值)
# service.max_retries -> 3(默认值,容器无此注册)

# ============ 循环依赖处理 ============

class UserService:
    def __init__(self, order_service: "OrderService"):  # 前向引用
        self.order_service = order_service

class OrderService:
    def __init__(self, user_service: UserService):  # 循环依赖!
        self.user_service = user_service

# 方式 1: 使用 Lazy 包装(推荐)
from symphra_container import Lazy

class UserService:
    def __init__(self, order_service: Lazy[OrderService]):  # 延迟注入
        self.order_service = order_service  # 首次访问时才解析

class OrderService:
    def __init__(self, user_service: UserService):
        self.user_service = user_service

container.register(UserService)
container.register(OrderService)
service = container.resolve(UserService)  # 成功!

# 方式 2: 属性注入
class UserService:
    def __init__(self):
        self.order_service: Optional[OrderService] = None

    def set_order_service(self, os: OrderService):
        self.order_service = os

container.register(UserService)
container.register(OrderService)
container.register_initializer(UserService, lambda us, os: us.set_order_service(os), [OrderService])

2.7 装饰器使用

from symphra_container import inject, injectable, Injected, Lazy

# ============ 类装饰器 ============

@injectable
class UserService:
    """默认 Lifetime.SINGLETON"""
    pass

@injectable(lifetime=Lifetime.TRANSIENT)
class RequestHandler:
    pass

@injectable.singleton
class Cache:
    pass

@injectable.transient
class Logger:
    pass

@injectable.scoped
class UnitOfWork:
    pass

@injectable.factory
def create_config():
    return Config.load()

# 自动注册到默认容器
# container.scan("myapp.services")

# ============ 方法/函数装饰器 ============

# 方式 1: 参数标记
@inject
def process_order(
    order: Order,
    payment_service: PaymentService = Injected,  # 从容器注入
    notification: NotificationService = Injected
):
    return payment_service.process(order)

# 调用时
order = Order(id=1)
result = process_order(order)  # 自动注入其他参数

# 方式 2: 显式参数名
@inject({"payment_service": PaymentService})
def process_order(order, payment_service):
    return payment_service.process(order)

# 方式 3: 使用容器实例
@inject(container=my_container)
def setup_database(db: Database = Injected):
    db.init()

# ============ 属性注入 ============

from typing import ClassVar

class UserService:
    container: ClassVar[Container]

    db: Database = inject()  # 使用描述符注入
    cache: Cache = inject("cache_service")  # 注入指定名称服务

    def __init__(self):
        pass  # db 和 cache 会自动注入

# 需要配置容器
UserService.container = container

2.8 FastAPI 集成

from symphra_container.integrations.fastapi import DIMiddleware, inject_dependencies

# ============ 中间件方式 ============

from fastapi import FastAPI

app = FastAPI()
container = Container()

# 注册服务
container.register(UserService)
container.register(Database)

# 添加 DI 中间件
app.add_middleware(DIMiddleware, container=container)

# 路由自动注入
@app.get("/users/{user_id}")
def get_user(
    user_id: int,
    user_service: UserService = Injected  # 自动从容器注入
):
    return user_service.get_user(user_id)

# ============ 装饰器方式 ============

@app.get("/orders/{order_id}")
@inject_dependencies(container)
def get_order(
    order_id: int,
    order_service: OrderService = Injected,
    logger: Logger = Injected
):
    logger.info(f"Getting order {order_id}")
    return order_service.get_order(order_id)

# ============ 异步支持 ============

@app.get("/async-users/{user_id}")
async def get_async_user(
    user_id: int,
    user_service: UserService = Injected
):
    return await user_service.get_user_async(user_id)

# ============ 请求作用域 ============

class RequestService:
    """每个请求创建一个实例"""
    def __init__(self):
        self.id = uuid4()

container.register(
    RequestService,
    lifetime=Lifetime.SCOPED
)

@app.get("/request-info")
def get_request_info(service: RequestService = Injected):
    return {"request_id": str(service.id)}

# 每个请求的 service.id 都不同

2.9 Flask 集成

from symphra_container.integrations.flask import FlaskContainer

# ============ Flask 扩展方式 ============

from flask import Flask

app = Flask(__name__)
container = FlaskContainer(app)

# 注册服务
container.register(UserService)
container.register(Database)

@app.route("/users/<user_id>")
@container.inject
def get_user(user_id, user_service: UserService = Injected):
    return user_service.get_user(user_id)

# ============ 应用上下文集成 ============

# 自动创建请求作用域
with app.app_context():
    service = container.resolve(RequestService)  # Scoped 实例

with app.test_request_context():
    service = container.resolve(RequestService)  # 新的 Scoped 实例

3. 完整使用示例

3.1 简单应用

from symphra_container import Container, Lifetime

# 初始化容器
container = Container()

# 定义服务
class Database:
    def __init__(self):
        print("Database initialized")

class UserRepository:
    def __init__(self, db: Database):
        self.db = db

class UserService:
    def __init__(self, repo: UserRepository):
        self.repo = repo

    def get_user(self, id: int):
        return f"User {id}"

# 注册服务
container.register(Database, lifetime=Lifetime.SINGLETON)
container.register(UserRepository)
container.register(UserService)

# 使用
service = container.resolve(UserService)
user = service.get_user(1)
print(user)  # User 1

3.2 复杂应用

from symphra_container import Container, Lifetime, inject, injectable

# 装饰器注册
@injectable.singleton
class Config:
    def __init__(self):
        self.debug = True
        self.db_url = "postgresql://..."

@injectable.singleton
class Database:
    def __init__(self, config: Config):
        self.config = config

@injectable
class Cache:
    pass

@injectable.transient
class RequestContext:
    def __init__(self, cache: Cache):
        self.cache = cache

@injectable.factory
def create_logger(config: Config):
    import logging
    return logging.getLogger("app")

# 容器配置
container = Container()
container.scan("myapp")  # 自动扫描并注册

# 使用
with container.create_scope() as scope:
    db = scope.resolve(Database)
    ctx = scope.resolve(RequestContext)
    logger = scope.resolve(Logger)

    # 在作用域内工作
    ...

3.3 字符串键混合使用

from symphra_container import Container

container = Container()

# 类型键注册
container.register(UserService)
container.register(Database)

# 字符串键注册
container.register("api_key", "sk_live_xxxxx")
container.register("max_connections", 100)
container.register_instance("config", load_config())

# 类型键解析
user_service = container.resolve(UserService)

# 字符串键解析
api_key: str = container.get("api_key")
max_conn: int = container.get("max_connections")
config: Config = container.get("config")

# 混合使用
class PaymentService:
    def __init__(self, api_key: str):
        self.api_key = api_key

def create_payment_service(container: Container):
    api_key = container.get("api_key")
    return PaymentService(api_key)

container.register_factory(PaymentService, create_payment_service)

4. 类型提示完整对应表

注册方式 获取方式 类型提示 IDE 自动补全
register(UserService) resolve(UserService) ✅ 完美 ✅ 完美
register(IService, Impl) resolve(IService) ✅ 完美 ✅ 完美
register("db", Database) get("db", Database) ✅ 完美 ✅ 可以
register("db", Database) db: Database = get("db") ✅ 完美 ✅ 可以
register_factory("logger", fn) get("logger", Logger) ✅ 完美 ✅ 可以
@injectable class Service resolve(Service) ✅ 完美 ✅ 完美
@inject decorator 自动注入参数 ✅ 完美 ✅ 完美

5. 错误处理

from symphra_container import (
    Container,
    ServiceNotFoundError,
    CircularDependencyError,
    InvalidServiceError,
    RegistrationError
)

try:
    # 服务未注册
    service = container.resolve(NonExistentService)
except ServiceNotFoundError as e:
    print(f"Error: {e}")  # Service NonExistentService not found

try:
    # 循环依赖
    service = container.resolve(CircularServiceA)
except CircularDependencyError as e:
    print(f"Error: {e}")  # Circular dependency detected: A -> B -> A

try:
    # 无效注册
    container.register(None, "invalid")
except InvalidServiceError as e:
    print(f"Error: {e}")

try:
    # 重复注册(override=False)
    container.register(Service, impl1)
    container.register(Service, impl2)  # override=False (default)
except RegistrationError as e:
    print(f"Error: {e}")  # Service already registered, use override=True

6. API 总结速查表

注册相关

  • register(service_type, impl=None, lifetime=SINGLETON, override=False) - 基础注册
  • register_factory(name, factory, lifetime=SINGLETON) - 工厂注册
  • register_instance(name, instance) - 实例注册
  • register_value(name, value) - 值注册
  • register_async_factory(name, async_factory) - 异步工厂
  • register_module(module) - 模块注册
  • scan(package) - 自动扫描注册

获取相关

  • resolve(service_type) - 解析类型
  • resolve_async(service_type) - 异步解析
  • get(key, service_type=None) - 获取(支持字符串和类型键)
  • get_async(key) - 异步获取
  • try_resolve(service_type) - 尝试解析,返回 Optional
  • try_get(key) - 尝试获取
  • get_all(service_type or pattern) - 获取所有

检查相关

  • has(key) - 检查服务是否存在
  • get_descriptor(key) - 获取服务描述符

删除相关

  • unregister(key, all=False) - 删除服务
  • try_unregister(key) - 尝试删除
  • clear(lifetime=None) - 清空容器
  • replace(old_key, new_impl) - 替换服务

作用域相关

  • create_scope() - 创建作用域
  • create_child() - 创建子容器
  • create_async_scope() - 创建异步作用域

装饰器相关

  • @injectable - 标记可注入类
  • @injectable.singleton - 单例标记
  • @injectable.transient - 瞬态标记
  • @injectable.scoped - 作用域标记
  • @inject - 方法注入装饰器
  • Injected - 参数注入标记
  • Lazy[T] - 延迟注入包装