injection 0.1.1

A lightweight dependency injection container for Rust applications
Documentation

Injection - 依赖注入容器

Injection 是一个基于宏的异步依赖注入容器,专为 Rust 应用程序设计。它使用 inventory 宏自动收集 Bean 定义,支持异步初始化和配置管理。

功能特性

  • 自动注册:使用 #[derive(Component)]#[derive(Service)] 宏自动注册组件
  • 异步初始化:支持异步工厂函数初始化组件
  • 配置管理:通过 #[configuration] 宏从配置文件加载配置
  • 依赖注入:自动解决依赖关系,支持字段级注入
  • 线程安全:所有组件都是 Send + Sync
  • 延迟初始化:使用 OnceCell 实现懒加载
  • Axum 集成:Service 宏支持 Axum 提取器,可直接在路由中使用

安装

Cargo.toml 中添加:

[dependencies]

injection = { path = "*" }

tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

serde = { version = "1", features = ["derive"] }

基本用法

1. 定义组件

使用 #[derive(Component)]#[derive(Service)] 宏标记结构体:

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. 初始化容器和使用组件

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

[database]

host = "localhost"

port = 5432

name = "mydb"



[server]

port = 8080

定义配置结构体:

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] 宏可以为异步函数自动生成无参版本,支持依赖注入:

use injection::{init, Component};

// 原始异步函数,参数会自动注入
#[init]
async fn initialize_database(
    #[config] config: DatabaseConfig,  // 从配置加载
) -> DatabasePool {
    DatabasePool::connect(&config.connection_string()).await
}

// 宏会生成一个 __initialize_database 无参函数
// 自动注入所有依赖并调用原始函数

自定义初始化逻辑

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 - 启用序列化/反序列化支持

完整示例

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