# Injection - 依赖注入容器
Injection 是一个基于宏的异步依赖注入容器,专为 Rust 应用程序设计。它使用 inventory 宏自动收集 Bean 定义,支持异步初始化和配置管理。
## 功能特性
- **自动注册**:使用 `#[derive(Component)]` 或 `#[derive(Service)]` 宏自动注册组件
- **异步初始化**:支持异步工厂函数初始化组件
- **配置管理**:通过 `#[configuration]` 宏从配置文件加载配置
- **依赖注入**:自动解决依赖关系,支持字段级注入
- **线程安全**:所有组件都是 `Send + Sync` 的
- **延迟初始化**:使用 `OnceCell` 实现懒加载
- **Axum 集成**:Service 宏支持 Axum 提取器,可直接在路由中使用
## 安装
在 `Cargo.toml` 中添加:
```toml
[dependencies]
injection = { path = "*" }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
serde = { version = "1", features = ["derive"] }
```
## 基本用法
### 1. 定义组件
使用 `#[derive(Component)]` 或 `#[derive(Service)]` 宏标记结构体:
```rust
use injection::{Component, Service};
use serde::Deserialize;
// 简单的数据访问对象
#[derive(Component, Clone)]
struct DatabaseConnection {
url: String,
}
impl DatabaseConnection {
fn new() -> Self {
DatabaseConnection {
url: "localhost:5432".to_string(),
}
}
}
// 服务层组件,自动注入 DatabaseConnection
#[derive(Component)]
struct UserService {
db: DatabaseConnection,
}
impl UserService {
fn get_user(&self, id: u32) -> String {
format!("User {} from {:?}", id, self.db.url)
}
}
// Service 宏还支持 Axum 提取器,可直接在路由中使用
#[derive(Service, Clone)]
struct AppController {
user_service: UserService,
}
```
### 2. 初始化容器和使用组件
```rust
use injection::InjectionContainer;
#[tokio::main]
async fn main() {
// 初始化容器(必须在异步上下文中)
InjectionContainer::init(|| {
// 可选的初始化回调
println!("容器初始化完成");
}).await;
// 同步获取组件(组件必须已预热完成)
let user_service = InjectionContainer::get::<UserService>();
println!("{}", user_service.get_user(1));
// 或者异步获取组件
let app_controller = InjectionContainer::get_async::<AppController>().await;
}
```
### 3. 使用配置
创建配置文件 `application.toml`:
```toml
[database]
host = "localhost"
port = 5432
name = "mydb"
[server]
port = 8080
```
定义配置结构体:
```rust
use injection::{configuration, Component};
use serde::Deserialize;
// 使用 #[configuration] 宏标记配置结构体
// 可以指定 prefix 参数,默认为结构体名称的下划线格式
#[configuration(prefix = "database")]
#[derive(Debug, Deserialize, Clone)]
struct DatabaseConfig {
host: String,
port: u16,
name: String,
}
// 如果不指定 prefix,默认使用结构体名称的下划线格式
// 例如:ServerConfig 默认为 "server_config"
#[configuration]
#[derive(Debug, Deserialize, Clone)]
struct ServerConfig {
port: u16,
}
// 在组件中使用配置
#[derive(Component)]
struct DatabasePool {
// 使用 #[config] 属性从配置加载字段
#[config]
config: DatabaseConfig,
}
impl DatabasePool {
fn connection_string(&self) -> String {
format!("{}:{}:{}", self.config.host, self.config.port, self.config.name)
}
}
```
## 高级用法
### 使用 init 宏
`#[init]` 宏可以为异步函数自动生成无参版本,支持依赖注入:
```rust
use injection::{init, Component};
// 原始异步函数,参数会自动注入
#[init]
async fn initialize_database(
#[config] config: DatabaseConfig, // 从配置加载
) -> DatabasePool {
DatabasePool::connect(&config.connection_string()).await
}
// 宏会生成一个 __initialize_database 无参函数
// 自动注入所有依赖并调用原始函数
```
### 自定义初始化逻辑
```rust
use injection::Component;
#[derive(Component)]
struct Cache {
capacity: usize,
}
impl Cache {
fn new() -> Self {
Cache { capacity: 1000 }
}
}
// 为单元结构体提供自定义实现
impl Component for Cache {
fn component_name() -> &'static str {
"cache"
}
async fn from_container() -> &'static Self {
Box::leak(Box::new(Cache::new()))
}
}
```
## API
### InjectionContainer
- `async init<F: FnOnce()>(init_fn: impl Into<Option<F>>)` - 异步初始化容器,可选的初始化回调
- `instance()` - 获取容器实例(同步)
- `get<T: Component>()` - 获取组件(同步,要求组件已初始化)
- `get_async<T: Component>()` - 获取组件(异步,可等待未初始化的组件)
### 宏
#### `#[derive(Component)]`
为结构体自动生成 Component trait 实现。
支持的字段属性:
- `#[config]` - 从配置文件加载字段值
- `#[init("fn_name")]` - 使用指定的异步函数初始化字段
#### `#[derive(Service)]`
与 Component 相同,但额外实现 Axum 提取器,可在路由处理器中直接使用。
#### `#[configuration(prefix = "xxx")]`
为配置结构体实现 Configure trait。
- 可选参数 `prefix` 指定配置文件中的键前缀
- 默认使用结构体名称的下划线格式(驼峰转下划线)
- 示例:
- `#[configuration(prefix = "database")]` - 明确指定前缀为 "database"
- `#[configuration]` - 使用默认前缀,如 `ServerConfig` -> "server_config"
#### `#[init]`
为异步函数生成无参版本,自动注入依赖。
- 支持 `#[config]` 参数属性,从配置加载参数
## 错误处理
- 容器未初始化时调用 `get()` 会 panic
- 获取不存在的组件会 panic
- Bean 无法 downcast 会 panic
- 配置文件不存在会使用默认值或使用回退配置
## 特性标志
- `full` - 启用所有功能(默认)
- `clap-config` - 支持命令行参数解析配置文件路径
- `config` - 启用配置管理功能
- `serde` - 启用序列化/反序列化支持
## 完整示例
```rust
use injection::{Component, Service, configuration, InjectionContainer};
use serde::Deserialize;
// 配置
#[configuration]
#[derive(Debug, Deserialize, Clone)]
struct ServerConfig {
port: u16,
}
// 数据库连接
#[derive(Component, Clone)]
struct Database {
url: String,
}
// 用户服务
#[derive(Component)]
struct UserService {
db: Database,
}
// 控制器(可用于 Axum)
#[derive(Service)]
struct UserController {
user_service: UserService,
#[config]
config: ServerConfig,
}
#[tokio::main]
async fn main() {
// 初始化容器
InjectionContainer::init(|| {
println!("应用启动");
}).await;
// 使用组件
let controller = InjectionContainer::get::<UserController>();
println!("服务器端口:{}", controller.config.port);
}
```
## 许可证
MIT