基于编译时工厂注册机制,我来为你设计一个支持两种生命周期的容器系统。这个设计将结合 inventory 和过程宏,实现类似 Java Spring 的 @Scope("prototype") 和 @Scope("singleton") 效果。

整体架构设计

text

┌─────────────────────────────────────────────────────┐
│                   Container                         │
│  ┌──────────────┐  ┌──────────────────────────┐   │
│  │  Registry    │  │    Instance Cache         │   │
│  │  (compile-   │  │    (runtime)              │   │
│  │   time)      │  │                           │   │
│  │              │  │  ┌─────────────────────┐ │   │
│  │  EntityA     │  │  │ Singleton Cache     │ │   │
│  │  EntityB     │  │  │  - EntityB: instance│ │   │
│  │  EntityC     │  │  └─────────────────────┘ │   │
│  │              │  │  ┌─────────────────────┐ │   │
│  │              │  │  │ Prototype Factory   │ │   │
│  │              │  │  │  - EntityA: fn()    │ │   │
│  │              │  │  │  - EntityC: fn()    │ │   │
│  │              │  │  └─────────────────────┘ │   │
│  └──────────────┘  └──────────────────────────┘   │
└─────────────────────────────────────────────────────┘

核心实现

1. 定义生命周期标记 Traits

rust

// 标记 trait:每次创建新实例
pub trait BaseEntity: 'static + Send + Sync {
    fn new() -> Self;
}

// 标记 trait:单例模式
pub trait BaseEntitySingle: 'static + Send + Sync {
    fn new() -> Self;
}

// 自动实现 trait 的辅助宏
pub trait EntityFactory: 'static + Send + Sync {
    fn create(&self) -> Box<dyn std::any::Any + Send + Sync>;
}

2. 编译时注册机制(使用 inventory)

rust

use inventory::submit;
use std::any::TypeId;

// 注册信息结构
pub struct EntityRegistration {
    pub type_id: TypeId,
    pub type_name: &'static str,
    pub scope: EntityScope,
    pub factory: Box<dyn EntityFactory>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EntityScope {
    Prototype,  // 每次新建
    Singleton,  // 单例
}

// 为两种生命周期创建独立的注册集合
inventory::collect!(EntityRegistration);

3. 过程宏实现自动注册

rust

// macros.rs
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

// 标记 BaseEntity(原型模式)
#[proc_macro_derive(BaseEntity)]
pub fn base_entity_derive(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let name = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
    
    let expanded = quote! {
        impl #impl_generics BaseEntity for #name #ty_generics #where_clause {
            fn new() -> Self {
                Self::default()
            }
        }
        
        // 自动实现 EntityFactory
        impl EntityFactory for #name {
            fn create(&self) -> Box<dyn std::any::Any + Send + Sync> {
                Box::new(#name::new())
            }
        }
        
        // 编译时注册
        const _: () = {
            use container::EntityRegistration;
            use container::EntityScope;
            
            inventory::submit! {
                EntityRegistration {
                    type_id: std::any::TypeId::of::<#name>(),
                    type_name: stringify!(#name),
                    scope: EntityScope::Prototype,
                    factory: Box::new(#name),
                }
            }
        };
    };
    
    TokenStream::from(expanded)
}

// 标记 BaseEntitySingle(单例模式)
#[proc_macro_derive(BaseEntitySingle)]
pub fn base_entity_single_derive(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let name = &input.ident;
    
    let expanded = quote! {
        impl BaseEntitySingle for #name {
            fn new() -> Self {
                Self::default()
            }
        }
        
        impl EntityFactory for #name {
            fn create(&self) -> Box<dyn std::any::Any + Send + Sync> {
                Box::new(#name::new())
            }
        }
        
        const _: () = {
            use container::EntityRegistration;
            use container::EntityScope;
            
            inventory::submit! {
                EntityRegistration {
                    type_id: std::any::TypeId::of::<#name>(),
                    type_name: stringify!(#name),
                    scope: EntityScope::Singleton,
                    factory: Box::new(#name),
                }
            }
        };
    };
    
    TokenStream::from(expanded)
}

4. Container 核心实现

rust

use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};

pub struct Container {
    // 单例缓存
    singleton_cache: Arc<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>,
    // 原型工厂缓存(直接从注册表获取)
    registry: Arc<Vec<EntityRegistration>>,
}

impl Container {
    pub fn new() -> Self {
        // 从 inventory 收集注册信息
        let registry: Vec<EntityRegistration> = inventory::iter::<EntityRegistration>
            .into_iter()
            .map(|r| r.clone())
            .collect();
        
        Container {
            singleton_cache: Arc::new(RwLock::new(HashMap::new())),
            registry: Arc::new(registry),
        }
    }
    
    // 获取实体(自动根据生命周期决定行为)
    pub fn get<T: Any + Send + Sync + Clone>(&self) -> Option<T> {
        let type_id = TypeId::of::<T>();
        let type_name = std::any::type_name::<T>();
        
        // 查找注册信息
        let registration = self.registry.iter().find(|r| r.type_id == type_id)?;
        
        match registration.scope {
            EntityScope::Prototype => {
                // 每次创建新实例
                self.create_prototype::<T>(registration)
            }
            EntityScope::Singleton => {
                // 返回单例
                self.get_singleton::<T>(type_id, registration)
            }
        }
    }
    
    fn create_prototype<T: Any + Send + Sync + Clone>(
        &self,
        registration: &EntityRegistration,
    ) -> Option<T> {
        // 使用工厂创建新实例
        let any_obj = registration.factory.create();
        any_obj.downcast::<T>().ok().map(|boxed| *boxed)
    }
    
    fn get_singleton<T: Any + Send + Sync + Clone>(
        &self,
        type_id: TypeId,
        registration: &EntityRegistration,
    ) -> Option<T> {
        // 先检查缓存
        {
            let cache = self.singleton_cache.read().unwrap();
            if let Some(instance) = cache.get(&type_id) {
                return instance.clone().downcast::<T>().ok().map(|boxed| *boxed);
            }
        }
        
        // 缓存未命中,创建新实例
        let any_obj = registration.factory.create();
        if let Ok(boxed) = any_obj.downcast::<T>() {
            let instance = *boxed;
            let arc_instance: Arc<dyn Any + Send + Sync> = Arc::new(instance.clone());
            
            // 存入缓存
            let mut cache = self.singleton_cache.write().unwrap();
            cache.insert(type_id, arc_instance);
            
            Some(instance)
        } else {
            None
        }
    }
    
    // 获取所有注册的类型名称(用于调试)
    pub fn list_registered_entities(&self) -> Vec<&'static str> {
        self.registry.iter().map(|r| r.type_name).collect()
    }
}

5. 使用示例

rust

use container::{Container, BaseEntity, BaseEntitySingle};

// 原型模式:每次获取都创建新实例
#[derive(Debug, Clone, Default, BaseEntity)]
pub struct UserEntity {
    pub id: u64,
    pub name: String,
}

impl UserEntity {
    pub fn new_with_name(name: &str) -> Self {
        UserEntity {
            id: rand::random(),
            name: name.to_string(),
        }
    }
}

// 单例模式:全局唯一实例
#[derive(Debug, Clone, Default, BaseEntitySingle)]
pub struct ConfigEntity {
    pub app_name: String,
    pub version: String,
}

impl ConfigEntity {
    pub fn load_from_env() -> Self {
        ConfigEntity {
            app_name: std::env::var("APP_NAME").unwrap_or("MyApp".to_string()),
            version: std::env::var("VERSION").unwrap_or("1.0.0".to_string()),
        }
    }
}

// 另一个原型实体
#[derive(Debug, Clone, Default, BaseEntity)]
pub struct SessionEntity {
    pub session_id: String,
    pub user_id: u64,
}

fn main() {
    let container = Container::new();
    
    println!("Registered entities: {:?}", container.list_registered_entities());
    
    // 测试原型模式
    let user1: Option<UserEntity> = container.get();
    let user2: Option<UserEntity> = container.get();
    
    if let (Some(u1), Some(u2)) = (user1, user2) {
        println!("User1 ID: {}, User2 ID: {}", u1.id, u2.id);
        println!("Are they the same instance? {}", std::ptr::eq(&u1, &u2));
        // 输出: Are they the same instance? false
    }
    
    // 测试单例模式
    let config1: Option<ConfigEntity> = container.get();
    let config2: Option<ConfigEntity> = container.get();
    
    if let (Some(c1), Some(c2)) = (config1, config2) {
        println!("Config1: {} v{}", c1.app_name, c1.version);
        println!("Config2: {} v{}", c2.app_name, c2.version);
        println!("Are they the same instance? {}", std::ptr::eq(&c1, &c2));
        // 输出: Are they the same instance? true
    }
    
    // 测试不同的原型实体
    let session1: Option<SessionEntity> = container.get();
    let session2: Option<SessionEntity> = container.get();
    
    if let (Some(s1), Some(s2)) = (session1, session2) {
        println!("Session1: {}, Session2: {}", s1.session_id, s2.session_id);
        println!("Different instances? {}", std::ptr::eq(&s1, &s2));
        // 输出: Different instances? false
    }
}

6. Cargo.toml 配置

toml

[dependencies]
inventory = "0.3"
once_cell = "1.19"
rand = "0.8"

[lib]
proc-macro = true

[package.metadata.inventory]
# inventory 配置

7. 增强:支持构造函数注入

rust

// 支持依赖注入的增强版本
pub trait EntityFactoryWithDeps: 'static + Send + Sync {
    fn create_with_deps(&self, container: &Container) -> Box<dyn Any + Send + Sync>;
}

// 在 Container 中添加依赖注入版本
impl Container {
    pub fn get_with_deps<T: Any + Send + Sync + Clone>(&self, deps: &[Box<dyn Any>]) -> Option<T> {
        // 实现带依赖的创建逻辑
        // ...
    }
}

8. 性能优化和最佳实践

rust

use std::sync::OnceLock;

// 全局单例容器
static CONTAINER: OnceLock<Container> = OnceLock::new();

impl Container {
    // 全局访问点
    pub fn global() -> &'static Container {
        CONTAINER.get_or_init(|| Container::new())
    }
}

// 使用全局容器
pub fn get_user_service() -> UserService {
    Container::global().get::<UserService>().unwrap()
}

关键特性总结

特性BaseEntity (Prototype)BaseEntitySingle (Singleton)
生命周期每次获取创建新实例全局唯一实例
内存管理调用者负责释放Container 持有所有权
线程安全每个线程独立需要内部同步
适用场景无状态的短暂对象配置、连接池、全局状态
性能每次分配新内存缓存命中,零分配

这个设计充分利用了 Rust 的编译期特性,将运行时决策最小化,保证了类型安全和零运行时开销的抽象。

更多推荐