# 依赖注入 (Dependency Injection) 实现文档

## 概述

本项目实现了一个轻量级的依赖注入容器，用于管理组件之间的依赖关系，提高代码的可测试性和可维护性。

## 主要组件

### 1. Container (`src/di/container.py`)

依赖注入容器，提供以下功能：

- **单例注册** (`register_singleton`): 注册单例服务，整个应用生命周期内只创建一次
- **工厂注册** (`register_factory`): 注册工厂服务，每次获取时创建新实例
- **实例注册** (`register_instance`): 直接注册已创建的实例
- **服务获取** (`get`): 根据名称获取服务实例
- **服务检查** (`has`): 检查服务是否已注册
- **重置** (`reset`): 重置单例实例（用于测试）

### 2. 全局容器

```python
from src.di import get_container, reset_container

# 获取全局容器（单例）
container = get_container()

# 获取服务
service = container.get("rag_service")

# 重置容器（仅用于测试）
reset_container()
```

### 3. ServiceProvider (`src/di/providers.py`)

服务提供者基类，用于组织服务注册逻辑：

```python
class MyServiceProvider(ServiceProvider):
    def register(self, container: Container):
        container.register_singleton("my_service", lambda: MyService())
    
    def boot(self, container: Container):
        # 在所有服务注册后执行初始化
        pass
```

## 默认注册的服务

| 服务名称 | 类型 | 描述 |
|----------|------|------|
| `config` | 单例 | 配置类 (`Config`) |
| `rag_service` | 单例 | RAG服务 (`RAGService`) |
| `rag_system` | 单例 | RAG系统 (`RAGSystem`) |
| `mcp_handlers` | 单例 | MCP处理器 (`MCPHandlers`) |

## 使用示例

### CLI 命令中使用

```python
from src.di import get_container

def cmd_query(args):
    container = get_container()
    service = container.get("rag_service")
    result = service.query(question=args.question)
```

### MCP 处理器中使用

```python
class MCPToolsHandler:
    def __init__(self, rag_service=None):
        if rag_service is None:
            from src.di import get_container
            container = get_container()
            rag_service = container.get("rag_service")
        self.service = rag_service
```

### 测试中使用

```python
from src.di import Container, reset_container

def test_my_feature():
    # 重置全局容器
    reset_container()
    
    # 创建测试专用容器
    container = Container()
    
    # 注册 mock 服务
    container.register_instance("rag_service", MockRAGService())
    
    # 测试逻辑...
```

## 架构优势

### 1. 解耦组件依赖

**之前**：
```python
# 全局变量，硬编码依赖
_service = RAGService()

def cmd_query(args):
    result = _service.query(...)
```

**之后**：
```python
# 通过容器获取，依赖可替换
def _get_service():
    return get_container().get("rag_service")

def cmd_query(args):
    service = _get_service()
    result = service.query(...)
```

### 2. 提高可测试性

```python
def test_cmd_query():
    # 可以注入 mock 服务
    reset_container()
    container = get_container()
    container.register_instance("rag_service", MockRAGService())
    
    # 测试命令
    cmd_query(args)
```

### 3. 懒加载

服务只在首次使用时才会被创建，避免不必要的初始化开销：

```python
container.register_singleton("rag_service", lambda: RAGService())
# RAGService 不会立即创建

service = container.get("rag_service")  # 首次获取时创建
service2 = container.get("rag_service")  # 返回同一实例
```

### 4. 线程安全

容器使用锁机制确保线程安全：

```python
class Singleton(Generic[T]):
    def __init__(self, factory):
        self._lock = Lock()  # 线程锁
    
    def get(self):
        with self._lock:
            if self._instance is None:
                self._instance = self._factory()
        return self._instance
```

## 最佳实践

### 1. 服务注册位置

- **核心服务**: 在 `container.py` 的 `_setup_default_services()` 中注册
- **可选服务**: 在首次使用时动态注册

### 2. 依赖注入方式

- **构造函数注入**: 优先使用，便于测试
- **容器直接获取**: 作为后备方案

```python
class MyHandler:
    def __init__(self, service=None):
        if service is None:
            service = get_container().get("service")
        self.service = service
```

### 3. 测试隔离

```python
def setup_function():
    reset_container()  # 每个测试前重置

def test_feature_a():
    # 测试 A

def test_feature_b():
    # 测试 B，不受 A 影响
```

## 扩展指南

### 添加新服务

1. 在 `_setup_default_services()` 中注册：

```python
def _setup_default_services(container):
    # 注册新服务
    container.register_singleton(
        "my_new_service",
        lambda: MyNewService()
    )
```

2. 或动态注册：

```python
container = get_container()
if not container.has("my_service"):
    container.register_singleton("my_service", create_my_service)
```

### 使用服务提供者

```python
from src.di.providers import ServiceProvider

class DatabaseProvider(ServiceProvider):
    def register(self, container):
        container.register_singleton("db", lambda: Database())
    
    def boot(self, container):
        db = container.get("db")
        db.connect()
```

## 相关文件

- `src/di/__init__.py` - 模块入口
- `src/di/container.py` - 容器实现
- `src/di/providers.py` - 服务提供者
- `test/test_di_container.py` - 测试文件
