Sylar服务器框架——配置模块

1、配置说明

  • 配置一般包含名称、值、类型、变更通知几项。其中名称对应一个字符串,必须唯一,不能与其他的配置冲突。类型可以是基本类型,也可以是复杂类型。关于值,最好给一个默认值,比如http默认端口是80。当配置项发生改变时,需要通知到使用该配置的代码。
    2、配置模块需要具有的功能
  • 可以定义配置项,也就是在提供配置名称、类型以及可选的默认值的情况下生成一个可用的配置项。由于一项配置可能在多个源文件中使用,所以配置模块还应该支持跨文件声明配置项的方法。
  • 应支持更新配置项的接口
  • 支持从配置文件中加载配置项,这里不仅应该支持基本数据类型的加载,也应该支持复杂数据类型的加载,比如直接从配置文件中加载一个map类型的配置项,或是直接从一个预定格式的配置文件中加载一个自定义结构体。
  • 支持配置项注册配置变更通知,配置模块应该提供方法让程序知道某项配置被修改了,以便于进行一些操作。比如对于网络服务器而言,如果服务器端口配置变化了,那程序应该重新起监听端口。这个功能一般是通过注册回调函数来实现的,配置使用方预先给配置项注册一个配置变更回调函数,配置项发生变化时,触发对应的回调函数以通知调用方。由于一项配置可能在多个地方引用,所以配置变更回调函数应该是一个数组的形式
  • 支持导出当前配置
    3、核心组件
  • ConfigVarBase: 配置项基类,虚基类,定义了配置项公有的成员和方法。sylar对每个配置项都包括名称和描述两项成员,以及toString/fromString两个纯虚函数方法。ConfigVarBase并不包含配置项类型和值,这些由继承类实现,由继承类实现的还包括具体类型的toString/fromString方法,用于和YAML字符串进行相互转换。
  • ConfigVar: 具体的配置参数类,继承自ConfigVarBase,并且是一个模板类,有3个模板参数。第一个模板参数是类型T,表示配置项的类型。另外两个模板参数是FromStr和ToStr,这两个参数是仿函数,FromStr用于将YAML字符串转类型T,ToStr用于将T转YAML字符串。这两个模板参数具有默认值LexicalCast<std::string, T>和LexicalCast<T, std::string>,根据不同的类型T,FromStr和ToStr具有不同的偏特化实现。ConfigVar类在ConfigVarBase上基础上包含了一个T类型的成员和一个变更回调函数数组,此外,ConfigVar还提供了setValue/getValue方法用于获取/更新配置值(更新配置时会一并触发全部的配置变更回调函数),以及addListener/delListener方法用于添加或删除配置变更回调函数。
  • Config: ConfigVar的管理类,负责托管全部的ConfigVar对象,单例模式。提供Lookup方法,用于根据配置名称查询配置项。如果调用Lookup查询时同时提供了默认值和配置项的描述信息,那么在未找到对应的配置时,会自动创建一个对应的配置项,这样就保证了配置模块定义即可用的特性。除此外,Config类还提供了LoadFromYaml和LoadFromConfDir两个方法,用于从YAML对象或从命令行-c选项指定的配置文件路径中加载配置。Config的全部成员变量和方法都是static类型,保证了全局只有一个实例。
    4、核心代码
    由于要支持从Yaml文件加载配置,一大难点就是既要支持普通类型又要支持想vector、list、set、map这些复杂类型。sylar的方法非常巧妙,使用模版类实现,并为每个类型实现了片特化。
/**
 * @brief 类型转换模板类(F 源类型, T 目标类型)
 */
template<class F, class T>
class LexicalCast {
public:
    /**
     * @brief 类型转换
     * @param[in] v 源类型值
     * @return 返回v转换后的目标类型
     * @exception 当类型不可转换时抛出异常
     */
    T operator()(const F& v) {
        return boost::lexical_cast<T>(v);
    }
};

/**
 * @brief 类型转换模板类偏特化(YAML String 转换成 std::vector<T>)
 */
template<class T>
class LexicalCast<std::string, std::vector<T> > {
public:
    std::vector<T> operator()(const std::string& v) {
        YAML::Node node = YAML::Load(v);
        typename std::vector<T> vec;
        std::stringstream ss;
        for(size_t i = 0; i < node.size(); ++i) {
            ss.str("");
            ss << node[i];
            vec.push_back(LexicalCast<std::string, T>()(ss.str()));
        }
        return vec;
    }
};

/**
 * @brief 类型转换模板类偏特化(std::vector<T> 转换成 YAML String)
 */
template<class T>
class LexicalCast<std::vector<T>, std::string> {
public:
    std::string operator()(const std::vector<T>& v) {
        YAML::Node node(YAML::NodeType::Sequence);
        for(auto& i : v) {
            node.push_back(YAML::Load(LexicalCast<T, std::string>()(i)));
        }
        std::stringstream ss;
        ss << node;
        return ss.str();
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值