配置管理
Config 模块提供基于 JSON 的配置系统,支持 CLI 参数解析、点分路径访问、类型安全的取值方法和验证。它与 App 框架集成,自动为每个服务提供独立的配置段。
概述
配置工作流遵循 定义 → 加载 → 访问 的模式:
- 定义预期的选项,包括类型、描述和默认值
- 从 JSON 文件和/或 CLI 参数加载(CLI 覆盖文件)
- 使用类型安全的 getter 和点分路径访问值
#include <xtils/config/config.h>
using namespace xtils;
Config config;
// 1. 定义选项
config.Define("server.host", "绑定地址", std::string("0.0.0.0"));
config.Define("server.port", "监听端口", int64_t(8080));
config.Define<bool>("server.ssl", "启用 TLS", false);
config.Define<std::string>("database.url", "数据库连接字符串", "", true); // 必填
// 2. 加载
config.ParseArgs(argc, argv); // 自动处理 --config-file
// 3. 访问
auto host = config.GetOr<std::string>("server.host", "0.0.0.0");
auto port = config.GetOr<int64_t>("server.port", 8080);头文件
#include "xtils/config/config.h"定义选项
Config& Define(const std::string& name, const std::string& description,
const Json& default_value, bool required = false);
template <typename T>
Config& Define(const std::string& name, const std::string& description,
T default_value, bool required = false);支持的类型:std::string、int64_t、double、bool、vector<int64_t>、vector<double>、vector<string>、vector<int>、vector<float>、Json。
加载
bool ParseArgs (int argc, const char** argv, bool allow_exit = false);
bool ParseArgs (const std::vector<std::string>& args, bool allow_exit = false);
bool LoadFile (const std::string& filename);
bool ParseJson (const Json& json);
bool Parse (const std::string& json_content);
size_t LoadEnv (const std::string& prefix);TIP
ParseArgs 会自动处理 --config-file <path> — 先加载 JSON 文件,然后将 CLI 参数作为覆盖值应用。
短选项(-x)
通过 Short(name, alias) 给已定义的选项追加单字符短名,便于命令行使用:
config.Define("server.port", "监听端口", int64_t(8080));
config.Short("server.port", "p");
// 启动: ./app -p 9000
// 等价于 --server.port 9000TIP
Short 总是作用于最近一次 Define 的选项;也可以在更便利的链式风格里直接接在 Define 后调用。
环境变量加载(LoadEnv)
把符合 <PREFIX>_<KEY> 模式的环境变量导入到 Config 中。变量名会被小写化,_ 转为 .:
// 假设环境: XTILS_LOG_LEVEL=2 XTILS_SERVER_PORT=9000
config.LoadEnv("XTILS");
config.Get<int64_t>("log.level"); // → 2
config.Get<int64_t>("server.port"); // → 9000返回值是实际匹配并解析成功的变量数。空 prefix 会导入全部环境变量(小写化),慎用。
访问(点分路径)
std::optional<std::string> GetString(const std::string& path) const;
std::optional<int64_t> GetInt(const std::string& path) const;
std::optional<double> GetDouble(const std::string& path) const;
std::optional<bool> GetBool(const std::string& path) const;
std::optional<Json> Get(const std::string& path) const;
template <typename T>
std::optional<T> Get(const std::string& path) const;
bool Has(const std::string& path) const;点分路径可遍历嵌套 JSON 对象:
// 给定: {"server": {"tls": {"cert": "/path/to/cert.pem"}}}
auto cert = config.GetString("server.tls.cert"); // → "/path/to/cert.pem"便捷访问:GetOr
GetOr<T> 简化了"获取值或使用默认值"的常见模式:
// 使用 Define() 时指定的默认值(若无值也无默认值则抛异常)
int64_t port = config.GetOr<int64_t>("server.port");
// 使用显式 fallback 值
std::string host = config.GetOr<std::string>("server.host", "0.0.0.0");
int workers = config.GetOr<int64_t>("workers", 4);对比传统写法:
// 旧写法
auto port = config.GetInt("server.port").value_or(8080);
// 新写法(更简洁,且 fallback 来自 Define 定义)
auto port = config.GetOr<int64_t>("server.port");修改
void Set(const std::string& path, const Json& value);
template <typename T>
void Set(const std::string& path, const T& value);验证与帮助
bool Validate() const; // 检查是否所有必填项都存在
std::vector<std::string> MissingRequired() const; // 缺失的必填字段列表
std::vector<std::string> NoParsed() const; // 未被识别的 CLI 参数列表
std::string Help() const; // 生成帮助文本序列化
std::string ToString() const;
Json ToJson() const;
bool Save(const std::string& filename) const;
void Print() const;配置热加载(ConfigWatcher)
ConfigWatcher(xtils/config/config_watcher.h)使用 inotify 监听文件变更,文件被改写时自动重新加载并触发回调。RAII 风格,析构时停止监听。
#include "xtils/config/config_watcher.h"
Config cfg;
cfg.LoadFile("/etc/app.json");
ConfigWatcher watcher(&cfg, &task_runner);
watcher.Watch("/etc/app.json", [](Config& cfg) {
LogI("config reloaded; new log level: %lld",
cfg.GetInt("log.level").value_or(0));
});
// 离开作用域时自动 Stop回调在 task_runner 所属线程上执行;Watch 重复调用会替换前一次监视。
v2.0 破坏性变更
旧版 config_compat.h 在 v2.0.0 已删除。所有 snake_case 包装(get/load_file/parse/define 等)一并移除,请改用 PascalCase API。
与 App 框架集成
使用 App 框架时,每个服务自动接收以其名称为 key 的配置段:
{
"api": {
"port": 8080,
"cors_origin": "*"
},
"database": {
"host": "localhost",
"port": 5432
}
}class ApiService : public Service<ApiService> {
public:
ApiService() : Service("api") {}
void Init() override {
// `config` 已预填充 "api" 段
auto port = config.GetOr<int64_t>("port", 8080);
auto cors = config.GetOr<std::string>("cors_origin", "*");
}
};完整示例
#include <xtils/config/config.h>
#include <xtils/logging/logger.h>
using namespace xtils;
int main(int argc, char** argv) {
Config config;
config.Define("server.host", "服务器绑定地址", std::string("0.0.0.0"));
config.Define("server.port", "服务器端口", int64_t(8080));
config.Define<bool>("server.ssl", "启用 SSL/TLS", false);
config.Define<std::string>("database.url", "数据库连接 URL", "", true);
config.Define("workers", "工作线程数", int64_t(4));
config.ParseArgs(argc, const_cast<const char**>(argv));
if (!config.Validate()) {
auto missing = config.MissingRequired();
for (auto& m : missing) {
LogE("缺少必填配置: %s", m.c_str());
}
LogI("\n%s", config.Help().c_str());
return 1;
}
auto host = config.GetOr<std::string>("server.host", "0.0.0.0");
auto port = config.GetOr<int64_t>("server.port", 8080);
LogI("在 %s:%lld 上启动服务器", host.c_str(), port);
config.Set("server.started_at", Json(time(nullptr)));
config.Save("runtime_config.json");
return 0;
}