< 返回版块

ZihanType 发表于 2023-09-11 18:51

Tags:依赖注入, dependency-injection, DI, IOC

Rudi

Rudi,一个开箱即用的依赖注入框架。

在之前的版本中,不管是依赖的生命周期是 Singleton 还是 Transient,每次从 Context 中取出的时候,都是一个有所有权的实例,这样的话,对于那些调用 clone 方法开销较大的 Singleton 类型,就会造成性能上的损失。之前的解决办法只能是包一层 RcArc,能用是能用,就是有点麻烦。

在 0.6.0 版本中,我新增了注入 Singleton 的引用的功能。之所以只有 Singleton,是因为 Singleton 的实例只有一个,取的自然是这个实例的引用;但是对于 Transient,每次都会创建一个新的实例,取引用的意义不大。

有了这个功能之后,框架的使用体验和性能都有了很大的提升。也算是践行“零抽象开销”的理念了。

示例

use std::cell::RefCell;

use rudi::{Context, Singleton};

// 引用计数
thread_local! {
    static COUNT: RefCell<usize> = RefCell::new(0);
}

fn inc_count() {
    COUNT.with(|c| {
        let mut c = c.borrow_mut();
        *c += 1;
    });
}

fn get_count() -> usize {
    COUNT.with(|c| {
        let c = c.borrow();
        *c
    })
}

// 一个假的 Serialize trait
trait FakeSerialize: Default {}

impl<T: Default> FakeSerialize for T {}

// 一个大的包含所有配置的类型
#[derive(Debug)]
struct AppConfig;

impl Clone for AppConfig {
    fn clone(&self) -> Self {
        // 如果调用了 AppConfig 的 clone 方法,引用计数加一
        inc_count();
        Self
    }
}

#[Singleton]
impl AppConfig {
    // 从文件中读取配置
    fn load_file() -> Self {
        Self
    }
}

// 从大的配置中读取各个配置
impl AppConfig {
    fn get<T: FakeSerialize>(&self) -> T {
        T::default()
    }
}

#[derive(Default, Clone)]
struct DbConfig;

#[Singleton]
impl DbConfig {
    // 一个简单的例子
    fn new(#[di(ref)] cfg: &AppConfig) -> Self {
        cfg.get()
    }
}

#[derive(Default, Clone)]
struct RedisConfig;

#[Singleton]
impl RedisConfig {
    // 一个使用 Option<&T> 的例子
    fn new(#[di(option, ref)] cfg: Option<&AppConfig>) -> Self {
        match cfg {
            Some(cfg) => cfg.get(),
            None => Self,
        }
    }
}

#[Singleton]
fn Run(_db_config: DbConfig, _redis_config: RedisConfig) {
    println!("run!");
}

fn main() {
    let mut cx = Context::auto_register();
    assert_eq!(get_count(), 0);
    cx.resolve::<()>();
    // 引用计数一直为 0,说明确实没有调用 clone 方法,都取的是引用
    assert_eq!(get_count(), 0);
}

更详细的功能说明可以看文档

Rudi

欢迎各位使用,有问题欢迎提 issue,如果觉得好用,可以点个 star。

评论区

写评论

还没有评论

1 共 0 条评论, 1 页