利用编译时工厂注册的机制, 开发一个container容器,对象如何继承成员BaseEntity则每次创建新实例,如果继续BaseEntitySingle 则每次返回相同 的对象
·
基于编译时工厂注册机制,我来为你设计一个支持两种生命周期的容器系统。这个设计将结合 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 的编译期特性,将运行时决策最小化,保证了类型安全和零运行时开销的抽象。
更多推荐
所有评论(0)