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

avatar
作者
猴君
阅读量:0

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();     } }; 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!