< 返回版块

zooshee 发表于 2025-08-15 16:15

Tags:依赖注入, dependency-injection, DI, IoC,framework

Hi,大家周五好verdure0.0.5版本发布啦!

0.0.5的版本中带来了一个较大的更新,verdure-context模块发布啦!拥有应用级的上下文管理和自动化配置管理,详情请见README.md

目前处于基础底座的打造期,期待有志之士加入一起做这件事。

快速使用

Configuration 自动读取配置文件

application.yml示例文件:

server:
  name: TestApp
  port: 8080
datasource:
  host: 127.0.0.1
  username: root
  password: 123456
  database: test

带有Configurationderive结构体会自动注册成Component自动读取配置并装载,若配置文件中不存在该键值则会使用config_defaultconfig_default_t,如果不存在默认值则为None。 需要注意的是字段类型必须使用Option<T>包装。

支持的配置格式

  • YAML: .yml, .yaml 文件
  • TOML: .toml 文件
  • Properties: .properties 文件

默认值属性

  • #[config_default(value)]: 提供字面量默认值
  • #[config_default_t(expression)]: 提供表达式默认值,支持复杂计算
use std::sync::Arc;
use verdure::event::{ContextAwareEventListener, ContextInitializingEvent};
use verdure::{ApplicationContext, ComponentFactory, Configuration, Component};

#[derive(Debug, Configuration)]
#[configuration("server")]
struct ServerConfig {
    // server.name
    name: Option<String>,
    // server.port
    #[config_default(8080)]
    port: Option<u32>,
}

#[derive(Debug, Configuration)]
#[configuration("datasource")]
struct DatasourceConfig {
    // datasource.host
    #[config_default_t(Some(get_host()))]
    host: Option<String>,
    // datasource.port
    #[config_default(3306)]
    port: Option<u32>,
    // datasource.username
    #[config_default("......")]
    username: Option<String>,
    // datasource.password
    #[config_default("......")]
    password: Option<String>,
    // datasource.database
    #[config_default("test_db")]
    database: Option<String>,
}

fn get_host() -> String {
    "127.0.0.1".to_string()
}

高级配置特性

配置优先级(从高到低):

  1. 运行时属性:通过 set_config() 设置的值
  2. 配置源:通过 add_config_source() 添加的源(后添加的优先)
  3. 环境变量:系统环境变量
  4. 配置文件:通过各种方法加载的文件

事件系统

  • ContextInitializingEvent: 上下文初始化开始时触发
  • ContextInitializedEvent: 上下文初始化完成时触发
  • ConfigurationChangedEvent: 配置改变时触发

ApplicationContext 初始化

struct ApplicationStartEvent;
impl ContextAwareEventListener<ContextInitializingEvent> for ApplicationStartEvent {
    fn on_context_event(&self, _event: &ContextInitializingEvent, context: &ApplicationContext) {
        let container = context.container();
        let datasource_config = container
            .get_component::<DatasourceConfig>()
            .expect("datasource config not found")
            .clone();
        // ... do something with datasource_config
        // context.register_component(Arc::new(datasource_component));
    }
}

fn init_context() -> Arc<ApplicationContext> {
    let context = ApplicationContext::builder()
        // 加载配置文件(支持 YAML、TOML、Properties 格式)
        .with_config_file("application.yml")
        .build();
    match context {
        Ok(context) => {
            context.subscribe_to_context_events(ApplicationStartEvent);
            match context.initialize() {
                Ok(_) => Arc::new(context),
                Err(e) => {
                    panic!("failed to initialize context: {}", e);
                }
            }
        }
        Err(e) => panic!("failed to new context: {}", e),
    }
}

#[derive(Component)]
struct TestA {
    #[autowired]
    test_b: Arc<TestB>,
    test_c: Option<TestC>,
    test_d: TestD
}

#[derive(Component)]
struct TestB {
    a: i32,
    b: i32,
}

fn main() {
    let context = init_context();
    let server_config = context
        .get_component::<ServerConfig>()
        .expect("datasource config not found");
    println!("server config: {:?}", server_config);
    // ... do something with context
    // get more component......
}

向诸位求一个Star,你的Star就是对我最好的支持! Verdure

评论区

写评论

还没有评论

1 共 0 条评论, 1 页