< 返回版块

duzhaosongyue 发表于 2022-01-24 13:26

Tags:yml、配置文件

在rust项目中使用yml配置文件

引言

​ 在接触rust之前一直是使用java,已经习惯了springboot那一套东西,所以对使用.env或者.toml做配置文件都不习惯。就想着复刻springboot的配置习惯,花了点时间做好了,就不知道自己做的怎么样,请诸位大佬指教。

第一步:创建项目

cargo new yml_rust

第二步:创建配置文件

cd yml_rust
mkdir resources  #经过实践我发现rust打包的时候不会包含配置文件,所以我建议配置文件和src文件夹平级这样方便在发布时复制配置文件
cd resources 
touch application.yml application-dev.yml application-test.yml application-prod.yml #创建配置配置文件 
# application.yml 环境配置文件 可以通过配置dev、test、prod切换配置
# application-dev.yml  开发环境配置
# application-test.yml 测试环境配置
# application-prod.yml 生产环境配置

编辑 application.yml 添加一下内容:

#切换配置文件
profiles:
  active: dev

编辑 application-dev.yml 添加一下内容:

# mysql 配置
mysql:
  host: 127.0.0.1
  port: 3306
  user: root
  password: jishuzhai
  db: rust_book
  #最小连接数
  pool_min_idle: 8
  #最大连接数
  pool_max_open: 32
  #连接超时时间单位秒
  timeout_seconds: 15

编辑 application-prod.yml 添加一下内容:

# mysql 配置
mysql:
  host: 127.0.0.2
  port: 3306
  user: root
  password: jishuzhai
  db: rust_book
  #最小连接数
  pool_min_idle: 8
  #最大连接数
  pool_max_open: 32
  #连接超时时间单位秒
  timeout_seconds: 15

编辑 application-test.yml 添加一下内容:

# mysql 配置
mysql:
  host: 127.0.0.3
  port: 3306
  user: root
  password: jishuzhai
  db: rust_book
  #最小连接数
  pool_min_idle: 8
  #最大连接数
  pool_max_open: 32
  #连接超时时间单位秒
  timeout_seconds: 15

注意dev和prod、test的差异只有ip地址不一样 这是为了后面测试切换功能

第三步:添加配置

在Cargo.toml文件中**[dependencies]**标签下添加一下配置:

serde = { version = "1.0.125", features = ["derive"] }
serde_json = "1.0.75"
lazy_static = "1.4.0"
serde_yaml = "0.8.23"
schemars = "0.8.8"

第四步:编写读取配置代码

cd /Users/fuping/Desktop/yml_rust/src 
mkdir load_config  #加载配置文件的代码模块
touch load_config/mod.rs load_config/models.rs load_config/init_load_config.rs
mkdir util         #全局变量
touch util/mod.rs util/constant.rs

编辑 load_config/mod.rs文件添加一下代码:

/****
 * 加载系统配置
 */
pub mod models;
pub mod init_load_config;

编辑load_config/models.rs 添加一下代码

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct GlobalConfig {
    pub mysql: Mysql,
}

#[derive(Debug,Serialize, Deserialize)]
pub struct Mysql {
    pub host: String,
    pub port: u32,
    pub user: String,
    pub password: String,
    pub db: String,
    pub pool_min_idle: u64,
    pub pool_max_open: u64,
    pub timeout_seconds: u64,
}

#[derive(Serialize, Deserialize)]
pub struct Profiles {
    pub active: String,
}

#[derive(Serialize, Deserialize)]
pub struct EnvConfig {
    pub profiles: Profiles,
}

编辑load_config/init_load_config.rs文件添加一下代码

use crate::load_config::models::{GlobalConfig, EnvConfig};
use schemars::schema::RootSchema;
use serde_yaml::from_str as yaml_from_str;
use serde_json::{from_str as json_from_str, to_string_pretty};
use std::fs::read_to_string;

///
/// 加载环境配置
///
///
fn load_env_conf() -> Option<EnvConfig> {
    let schema = yaml_from_str::<RootSchema>(
        &read_to_string("resources/application.yml").expect("Error loading configuration file resources/application.yml, please check the configuration!"),
    );
    return match schema {
        Ok(json) => {
            let data = to_string_pretty(&json).expect("resources/application.yml file data error!");
            let p: EnvConfig = json_from_str(&*data).expect("Failed to transfer JSON data to EnvConfig object!");
            return Some(p);
        }
        Err(err) => {
            println!("{}", err);
            None
        }
    };
}

///
/// 根据环境配置加载全局配置
/// action  dev 开始环境 test 测试环境 prod 生产环境
///
fn load_global_config(action: String) -> Option<GlobalConfig> {
    let path = format!("resources/application-{}.yml", &action);
    let schema = yaml_from_str::<RootSchema>(
        &read_to_string(&path).unwrap_or_else(|_| panic!("Error loading configuration file {}, please check the configuration!", &path)),
    );
    return match schema {
        Ok(json) => {
            let data = to_string_pretty(&json).unwrap_or_else(|_| panic!("{} file data error!, please check the configuration!", path));
            let p = json_from_str(&*data).expect("Failed to transfer JSON data to BriefProConfig object!");
            return Some(p);
        }
        Err(err) => {
            println!("{}", err);
            None
        }
    };
}

///
/// 先加载环境配置 在根据当前加载的环境 去加载相应的信息
///
pub fn load_conf() -> Option<GlobalConfig> {
    println!("{}", "Load profile");
    if let Some(init) = load_env_conf() {
        return load_global_config(init.profiles.active);
    }
    None
}


#[test]
fn test_load_env_conf_mysql() {
    let pro = load_conf();
    pro.as_ref().map(|a| {
        println!("mysqlConfig:{}", serde_json::to_string(&a.mysql).unwrap());
    });
}

第五步:测试

运行test_load_env_conf_mysql 测试看看运行结果,正常情况下会打印一下结果:

Load profile
mysqlConfigs:{"host":"127.0.0.1","port":3306,"user":"root","password":"jishuzhai","db":"rust_book","pool_min_idle":8,"pool_max_open":32,"timeout_seconds":15}

然后编辑application.yml 更改配置查看配置切换是否正常。

在项目中使用:

编辑util/mod.rs 文件添加以下内容:

pub mod constant;

编辑util/constant.rs文件添加以下内容:

use lazy_static::lazy_static;
use crate::load_config::models::GlobalConfig;
use crate::load_config::init_load_config::load_conf;

lazy_static! {
    ///
    /// 全局配置
    ///
    pub static ref GLOBAL_CONFIG: GlobalConfig = load_conf().unwrap();
}

编辑main.rs 添加以下内容

mod load_config;
mod util;

use util::constant::GLOBAL_CONFIG;

fn main() {
    let config = &GLOBAL_CONFIG;
    println!("{:?}", config.mysql);
}

运行项目

cargo run

运行结果如下:

Load profile

Mysql { host: "127.0.0.3", port: 3306, user: "root", password: "jishuzhai", db: "rust_book", pool_min_idle: 8, pool_max_open: 32, timeout_seconds: 15 }

yml_rust完整代码可以在github上找到

评论区

写评论
jmjoy 2022-01-25 11:34

生产的话,springboot的配置丢到配置中心比较好。

作者 duzhaosongyue 2022-01-25 09:01

受教了,🙏

👇
ruby: 你这 application-test.yml 和 application-dev.yml 内容基本都是一样

无论是 Rust 还是 Go 社区配置的最佳实践都是 默认配置项 + config merge

  1. 首先配置结构体从默认值开始构造
  2. 如果提供了配置文件,读取配置文件并更新
  3. 如果命令行参数有 --server.addr 之类的配置项,merge 该配置
  4. 如果环境变量有 SERVER_ADDR 之类配置,进行 merge

所以同一个配置,例如 rustc 的 RUST_TEST_THREADS 既可以在命令行参数配置也可以在环境变量,也可以在配置文件

这样的话,我的 test 环境配置文件只需要一行就够了,例如只有 mysql 不一样,就写一行 port: 13307 配置就够了,不会全量的写配置文件的

ruby 2022-01-24 16:32

你这 application-test.yml 和 application-dev.yml 内容基本都是一样

无论是 Rust 还是 Go 社区配置的最佳实践都是 默认配置项 + config merge

  1. 首先配置结构体从默认值开始构造
  2. 如果提供了配置文件,读取配置文件并更新
  3. 如果命令行参数有 --server.addr 之类的配置项,merge 该配置
  4. 如果环境变量有 SERVER_ADDR 之类配置,进行 merge

所以同一个配置,例如 rustc 的 RUST_TEST_THREADS 既可以在命令行参数配置也可以在环境变量,也可以在配置文件

这样的话,我的 test 环境配置文件只需要一行就够了,例如只有 mysql 不一样,就写一行 port: 13307 配置就够了,不会全量的写配置文件的

1 共 3 条评论, 1 页