重写sylar服务器框架:配置模块

sylar服务器框架:配置模块

模块概述

可用于定义/声明配置项,并且从配置文件(YAML文件)中加载用户配置。一个配置项包含名称(对应着一个字符串,必须唯一,不能与其他配置项产生冲突),类型(支持基本类型和复杂类型,自定义类型需要做偏特化),值,配置项描述。

采用约定优于配置,也称作按约定编程,是一种软件设计范式,旨在减少软件开发人员需做决定的数量,获得简单的好处,而又不失灵活性。

模块功能

  1. 支持定义/声明配置项,在提供配置名称,配置类型,默认值,配置项描述的情况下生成一个可用的配置项。
  2. 支持更新配置项的值。
  3. 支持从预设置的路径中的配置文件加载配置项。可支持基本数据类型的加载,支持复杂数据类型的加载和自定义结构体的加载。
  4. 支持导出当前项目的配置项。

简单例子

servers:
    - address: ["0.0.0.0:8090"]
      keepalive: 1
      timeout: 1000
      name: sylar/1.1
// 自定义类型
struct HttpServerConf
    {
        std::vector<std::string> address;
        int keepalive = 0;
        int timeout = 1000 * 2 * 60;
        std::string name;

        bool isValid() const
        {
            return !address.empty();
        }

        bool operator==(const HttpServerConf &oth) const
        {
            return address == oth.address &&
                   keepalive == oth.keepalive &&
                   timeout == oth.timeout &&
                   name == oth.name;
        }
    };
// 偏特化
template <>
    class LexicalCast<std::string, HttpServerConf>
    {
    public:
        HttpServerConf operator()(const std::string &val)
        {
            YAML::Node node = YAML::Load(val);
            HttpServerConf conf;
            conf.keepalive = node["keepalive"].as<int>(conf.keepalive);
            conf.timeout = node["timeout"].as<int>(conf.timeout);
            conf.name = node["name"].as<std::string>(conf.name);
            if (node["address"].IsDefined())
            {
                for (size_t i = 0; i < node["address"].size(); ++i)
                {
                    conf.address.push_back(node["address"][i].as<std::string>());
                }
            }

            return conf;
        }
    };

    template <>
    class LexicalCast<HttpServerConf, std::string>
    {
    public:
        std::string operator()(const HttpServerConf &conf)
        {
            YAML::Node node;
            node["name"] = conf.name;
            node["keepalive"] = conf.keepalive;
            node["timeout"] = conf.timeout;
            for (auto &i : conf.address)
            {
                node["address"].push_back(i);
            }
            std::stringstream ss;
            ss << node;
            return ss.str();
        }
    };
// 声明配置项
static sylar::ConfigVar<std::vector<HttpServerConf>>::ptr g_http_servers_conf =
        sylar::Config::Lookup("http_servers", std::vector<HttpServerConf>(), "http server config");
// 加载配置文件
YAML::Node root = YAML::LoadFile("/xx/xx.yml");
sylar::Config::LoadFromYaml(root);

模块分析

重写sylar服务器框架:配置模块_第1张图片

ConfigVarBase:配置项虚基类,定义配置项公有的成员和方法。sylar对每个配置项都包括名称和描述两项成员变量,以及toString和fromString两个纯虚函数成员方法。

template<class T,
		 class FromStr = LexicalCast<std::string, T>
         class ToStr = LexicalCast<T, std::string>>
class ConfigVar : public ConfigVarBase
{
    ...
  	typedef std::function<void(const T &old_value, const T &new_value)> on_change_cb;
    ...
};

ConfigVar:配置参数类,继承自ConfigVarBase类,并且是一个模板类,有3个模板参数。第一个模板参数是类型T,表示配置项的类型。另外两个模板参数是FromStr和ToStr,这两个参数是仿函数,FromStr用于将YAML字符串转类型T,ToStr用于将T转YAML字符串。这两个模板参数具有默认值LexicalCastLexicalCast,根据不同的类型T,FromStr和ToStr具有不同的偏特化实现。

ConfigVar类在ConfigVarBase上基础上包含了一个T类型的成员和一个变更回调函数数组,此外,ConfigVar还提供了setValue/getValue方法用于获取/更新配置值(更新配置时会一并触发全部的配置变更回调函数),以及addListener/delListener方法用于添加或删除配置变更回调函数。

全部的配置变更回调函数),以及addListener/delListener方法用于添加或删除配置变更回调函数。

Config:ConfigVar的管理类,负责托管全部的ConfigVar对象,单例模式。提供Lookup方法,用于根据配置名称查询配置项。如果调用Lookup查询时同时提供了默认值和配置项的描述信息,那么在未找到对应的配置时,会自动创建一个对应的配置项,这样就保证了配置模块定义即可用的特性。除此外,Config类还提供了LoadFromYaml和LoadFromConfDir两个方法,用于从YAML对象或从命令行-c选项指定的配置文件路径中加载配置。Config的全部成员变量和方法都是static类型,保证了全局只有一个实例。

你可能感兴趣的:(服务器,c++)