服务器配置系统主要作用是为服务器提供便利的服务,体现约定大于配置的思想。比如为日志系统配置日志器、日志输出器、日志格式器等,省去了大量的定义语句。此处使用的配置文件为yml,通过yaml-cpp库进行解析,并用片特化的方式为大量数据类型实现序列化与反序列化,同时用回调函数的机制使得配置生效。
ConfigVarBase基类
此类主要为各个配置项定义基类,主要包括配置项的名称以及描述,为子类定义的核心方法为toString()与fromString()。主要用于序列化与反序列化。m_name为配置名称,存储使用小写。
std::transform(m_name.begin(), m_name.end(), m_name.begin(), ::tolower
m_description为配置参数的描述
class ConfigVarBase {
public:
typedef std::shared_ptr<ConfigVarBase> ptr;
/**
* @brief 构造函数
* @param[in] name 配置参数名称[0-9a-z_.]
* @param[in] description 配置参数描述
*/
ConfigVarBase(const std::string& name, const std::string& description = "")
:m_name(name)
,m_description(description) {
std::transform(m_name.begin(), m_name.end(), m_name.begin(), ::tolower);
}
virtual std::string getTypeName() const = 0;
/**
* @brief 析构函数
*/
virtual ~ConfigVarBase() {}
/**
* @brief 返回配置参数名称
*/
const std::string& getName() const { return m_name;}
/**
* @brief 返回配置参数的描述
*/
const std::string& getDescription() const { return m_description;}
/**
* @brief 转成字符串
*/
virtual std::string toString() = 0;
/**
* @brief 从字符串初始化值
*/
virtual bool fromString(const std::string& val) = 0;
/**
* @brief 返回配置参数值的类型名称
*/
//virtual std::string getTypeName() const = 0;
protected:
/// 配置参数的名称
std::string m_name;
/// 配置参数的描述
std::string m_description;
};
ConfigVar模版类
ConfigVar类是继承ConfigVarBase,是一个模版类,使用模版类是因为配置项可能是多种类型的,比如int,float,map,vector甚至还可能是自定义类型,比如说对日志系统进行配置就需要对自定义的日志系统进行片特化。
在template中T表示不同类型的配置参数,class FromStr=LexicalCast<std::string,T>是反序列化的片特化代表,class ToStr=LexicalCast<T,std::string>是序列化的片特化代表。分别表示对不同类型的配置参数进行序列化与反序列化。
在toString()函数中进行ToStr()(m_val)调用表示对T类型的配置参数进行序列化转换,具体使用的模版序列化类需要自己定义。同理在fromString()函数中的FromStr()(val)将string转化为T类型的配置参数,同时在fromString()函数中对于转换而来的T类型配置参数直接用setValue存储在自身的m_val中,这也就表示读取到的配置参数正式存储了起来。
在ConfigVar类中定义了回调函数机制,使用function定义回调函数类型,并在类中使用map中用唯一的uint64_t来标识回调函数。回调机制定义在ConfigVar类中是为了单独为每一项定义回调函数。
使用addListener(),delListener(),getListener(),clearListener()来管理回调函数。而回调函数真正调用是在setvalue函数中,表明在m_val更新的同时,也调用回调函数去通知配置更新。
typedef std::function<void (const T& old_value, const T& new_value)> on_change_cb;
std::map<uint64_t, on_change_cb> m_cbs;
sylar::ConfigVar<std::set<LogDefine> >::ptr g_log_defines =
sylar::Config::Lookup("logs", std::set<LogDefine>(), "logs config");//添加logs配置选项。
g_log_defines->addListener([](const std::set<LogDefine>& old_value,
const std::set<LogDefine>& new_value){
std::cout<<"add logs"<<std::end;
})//为logs配置选项添加回调函数,可以使得m_val中的参数设置到loggerManager中去,也就使得配置真正生效了。template<class T,class FromStr=LexicalCast<std::string,T>,class ToStr=LexicalCast<T,std::string> >
class ConfigVar : public ConfigVarBase {
public:
// typedef RWMutex RWMutexType;
typedef std::shared_ptr<ConfigVar> ptr;
typedef std::function<void (const T& old_value, const T& new_value)> on_change_cb;
/**
* @brief 通过参数名,参数值,描述构造ConfigVar
* @param[in] name 参数名称有效字符为[0-9a-z_.]
* @param[in] default_value 参数的默认值
* @param[in] description 参数的描述
*/
ConfigVar(const std::string& name
,const T& default_value
,const std::string& description = "")
:ConfigVarBase(name, description)
,m_val(default_value) {
}
/**
* @brief 将参数值转换成YAML String
* @exception 当转换失败抛出异常
*/
std::string toString() override {
try {
//return boost::lexical_cast<std::string>(m_val);
// RWMutexType::ReadLock lock(m_mutex);
return ToStr()(m_val);
} catch (std::exception& e) {
SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "ConfigVar::toString exception "
<< e.what() << " convert: " //<< TypeToName<T>() << " to string"
<< " name=" << m_name;
}
return "";
}
/**
* @brief 从YAML String 转成参数的值
* @exception 当转换失败抛出异常
*/
bool fromString(const std::string& val) override {
try {
//m_val=boost::lexical_cast<T>(val);
//std::cout<<"yes1199911 "<<val<<" "<<m_val<<std::endl;
setValue(FromStr()(val));
std::cout<<"yes1199911 "<<this->toString()<<std::endl;
} catch (std::exception& e) {
// std::cout<<"yes11311ooooo"<<std::endl;
SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "ConfigVar::fromString exception "
<< e.what() << " convert: string to " //<< TypeToName<T>()
<< " name=" << m_name
<< " - " << val;
}
return false;
}
/**
* @brief 获取当前参数的值
*/
const T getValue() {
// RWMutexType::ReadLock lock(m_mutex);
return m_val;
}
/**
* @brief 设置当前参数的值
* @details 如果参数的值有发生变化,则通知对应的注册回调函数
*/
void setValue(const T& v) {
{
// RWMutexType::ReadLock lock(m_mutex);
if(v == m_val) {
std::cout<<"woqu "<<this->toString()<<std::endl;
return;
}
for(auto& i : m_cbs) {
i.second(m_val, v);
}
}
// RWMutexType::WriteLock lock(m_mutex);
m_val = v;
}
/**
* @brief 添加变化回调函数
* @return 返回该回调函数对应的唯一id,用于删除回调
*/
uint64_t addListener(on_change_cb cb) {
static uint64_t s_fun_id = 0;
// RWMutexType::WriteLock lock(m_mutex);
++s_fun_id;
m_cbs[s_fun_id] = cb;
return s_fun_id;
}
/**
* @brief 删除回调函数
* @param[in] key 回调函数的唯一id
*/
void delListener(uint64_t key) {
// RWMutexType::WriteLock lock(m_mutex);
m_cbs.erase(key);
}
/**
* @brief 获取回调函数
* @param[in] key 回调函数的唯一id
* @return 如果存在返回对应的回调函数,否则返回nullptr
*/
on_change_cb getListener(uint64_t key) {
// RWMutexType::ReadLock lock(m_mutex);
auto it = m_cbs.find(key);
return it == m_cbs.end() ? nullptr : it->second;
}
/**
* @brief 清理所有的回调函数
*/
void clearListener() {
// RWMutexType::WriteLock lock(m_mutex);
m_cbs.clear();
}
std::string getTypeName() const override {
//return TypeToName<T>();
return "";
}
private:
// RWMutexType m_mutex;
T m_val;
std::map<uint64_t, on_change_cb> m_cbs;
};
片特化模版类定义
这些类使得在Configvar中序列化与反序列化生效。
template<class F,class T>
class LexicalCast{
public:
T operator () (const F & v){
return boost::lexical_cast<T>(v);
}
};
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;
}
};
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);
std::stringstream ss;
for(auto& i : v)
// for(size_t i=0;i<v.size();i++)
{
node.push_back(YAML::Load(LexicalCast<T, std::string>()(i)));
// node.push_back(YAML::Load(LexiCalCast<T,std::string>()(v[i])));
}
ss<<node;
return ss.str();
}
};
template<class T>
class LexicalCast<std::string,std::list<T> >{
public:
std::list<T> operator () (const std::string & v){
YAML::Node node = YAML::Load(v);
typename std::list<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;
}
};
template<class T>
class LexicalCast<std::list<T>,std::string>{
public:
std::string operator () (const std::list<T> & v){
YAML::Node node(YAML::NodeType::Sequence);
std::stringstream ss;
for(auto & i: v)
//for(size_t i=0;i<v.size();i++)
{
node.push_back(YAML::Load(LexicalCast<T, std::string>()(i)));
// node.push_back(YAML::Load(LexicalCast<T,std::string>()(v[i])));
}
ss<<node;
return ss.str();
}
};
template<class T>
class LexicalCast<std::string,std::set<T> >{
public:
std::set<T> operator () (const std::string & v){
YAML::Node node = YAML::Load(v);
typename std::set<T> vec;
std::stringstream ss;
for(size_t i=0;i<node.size();i++){
ss.str("");
ss<<node[i];
vec.insert(LexicalCast<std::string,T>()(ss.str()));
}
return vec;
}
};
template<class T>
class LexicalCast<std::set<T>,std::string>{
public:
std::string operator () (const std::set<T> & v){
YAML::Node node(YAML::NodeType::Sequence);
std::stringstream ss;
// for(size_t i=0;i<v.size();i++)
for(auto& i: v)
{
node.push_back(YAML::Load(LexicalCast<T, std::string>()(i)));
// node.push_back(LexiCalCast<T,std::string>()(i));
}
ss<<node;
return ss.str();
}
};
template<class T>
class LexicalCast<std::string,std::unordered_set<T> >{
public:
std::unordered_set<T> operator() (const std::string & v){
YAML::Node node=YAML::Load(v);
std::stringstream ss;
std::unordered_set<T> vec;
for(size_t i=0;i<node.size();i++)
{
ss.str("");
ss<<node[i];
vec.insert(LexicalCast<std::string,T>()(ss.str()));
}
return vec;
}
};
template<class T>
class LexicalCast<std::unordered_set<T>, std::string> {
public:
std::string operator()(const std::unordered_set<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();
}
};
/**
* @brief 类型转换模板类片特化(YAML String 转换成 std::map<std::string, T>)
*/
template<class T>
class LexicalCast<std::string, std::map<std::string, T> > {
public:
std::map<std::string, T> operator()(const std::string& v) {
YAML::Node node = YAML::Load(v);
typename std::map<std::string, T> vec;
std::stringstream ss;
for(auto it = node.begin();
it != node.end(); ++it) {
ss.str("");
ss << it->second;
vec.insert(std::make_pair(it->first.Scalar(),
LexicalCast<std::string, T>()(ss.str())));
}
return vec;
}
};
/**
* @brief 类型转换模板类片特化(std::map<std::string, T> 转换成 YAML String)
*/
template<class T>
class LexicalCast<std::map<std::string, T>, std::string> {
public:
std::string operator()(const std::map<std::string, T>& v) {
YAML::Node node(YAML::NodeType::Map);
for(auto& i : v) {
node[i.first] = YAML::Load(LexicalCast<T, std::string>()(i.second));
}
std::stringstream ss;
ss << node;
return ss.str();
}
};
template<class T>
class LexicalCast<std::string,std::unordered_map<std::string,T> >{
public:
std::unordered_map<std::string,T> operator() (const std::string& v){
YAML::Node node=YAML::Load(v);
typename std::unordered_map<std::string,T> vec;
std::stringstream ss;
for(auto it=node.begin();it!=node.end();it++){
ss.str("");
ss<<it->second;
vec.insert(std::make_pair(it->first.Scalar(),LexicalCast<std::string, T>()(ss.str())));
// vec[it->first]=LexicalCast<std::string,T>(ss.str());
}
return vec;
}
};
template<class T>
class LexicalCast<std::unordered_map<std::string,T>,std::string>
{
public:
std::string operator () (const std::unordered_map<std::string,T>& v)
{
YAML::Node node(YAML::NodeType::Map);
for(auto& i:v){
node[i.first] =YAML::Load(LexicalCast<T, std::string>()(i.second));
}
std::stringstream ss;
ss << node;
return ss.str();
}
};
Config管理类
Config类对配置参数ConfigVar类进行统一管理,使用静态函数的方式去定义静态map来管理ConfigVar类,并用配置项名称来唯一标识。使用GetDatas()内部来定义ConfigVarMap类型,是为了防止其他静态类型调用s_datas时还未定义,所以写在函数里保证了s_datas在获取时一定定义了。
typedef std::unordered_map<std::string, ConfigVarBase::ptr> ConfigVarMap;
static ConfigVarMap& GetDatas() {
static ConfigVarMap s_datas;
return s_datas;
}
两个 LookUp函数分别在s_datas中添加以及查找对应的配置类。在第一个LookUp中,首先在s_datas中查找是否存在,如果存在看添加的类型是否与ConfigVar中的类型一致,如果一致则告知已经存在,如果不一致则输出错误。如果在s_datas中不存在则判断在配置类名称中是否存在不符合定义字符,如果通过则进行在s_datas添加。在第二个LookUp中只是用配置名在s_datas中进行查找,如果存在则返回智能指针。
class Config {
public:
typedef std::unordered_map<std::string, ConfigVarBase::ptr> ConfigVarMap;
// typedef RWMutex RWMutexType;
/**
* @brief 获取/创建对应参数名的配置参数
* @param[in] name 配置参数名称
* @param[in] default_value 参数默认值
* @param[in] description 参数描述
* @details 获取参数名为name的配置参数,如果存在直接返回
* 如果不存在,创建参数配置并用default_value赋值
* @return 返回对应的配置参数,如果参数名存在但是类型不匹配则返回nullptr
* @exception 如果参数名包含非法字符[^0-9a-z_.] 抛出异常 std::invalid_argument
*/
template<class T>
static typename ConfigVar<T>::ptr Lookup(const std::string& name,
const T& default_value, const std::string& description = "") {
// RWMutexType::WriteLock lock(GetMutex());
auto it = GetDatas().find(name);
if(it != GetDatas().end()) {
auto tmp = std::dynamic_pointer_cast<ConfigVar<T> >(it->second);
if(tmp) {
SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "Lookup name=" << name << " exists";
return tmp;
} else {
SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "Lookup name=" << name << " exists but type not ";
// << TypeToName<T>() << " real_type=" << it->second->getTypeName()
// << " " << it->second->toString();
return nullptr;
}
}
if(name.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._012345678")
!= std::string::npos) {
SYLAR_LOG_ERROR(SYLAR_LOG_ROOT()) << "Lookup name invalid " << name;
throw std::invalid_argument(name);
}
typename ConfigVar<T>::ptr v(new ConfigVar<T>(name, default_value, description));
GetDatas()[name] = v;
return v;
}
/**
* @brief 查找配置参数
* @param[in] name 配置参数名称
* @return 返回配置参数名为name的配置参数
*/
template<class T>
static typename ConfigVar<T>::ptr Lookup(const std::string& name) {
// RWMutexType::ReadLock lock(GetMutex());
auto it = GetDatas().find(name);
if(it == GetDatas().end()) {
return nullptr;
}
return std::dynamic_pointer_cast<ConfigVar<T> >(it->second);
}
/**
* @brief 使用YAML::Node初始化配置模块
*/
static void LoadFromYaml(const YAML::Node& root);
/**
* @brief 查找配置参数,返回配置参数的基类
* @param[in] name 配置参数名称
*/
static ConfigVarBase::ptr LookupBase(const std::string& name);
static void ALL(){
auto s=GetDatas();
for(auto & i: s){
std::cout<<i.first<<std::endl;
}
}
private:
/**
* @brief 返回所有的配置项
*/
static ConfigVarMap& GetDatas() {
static ConfigVarMap s_datas;
return s_datas;
}
};在Config类中LoadFromYaml函数可以对yml文件进行解析,由于遵守约定大于配置的原则,如果解析出来的配置选项在s_data中存在的话,就用fromstring()对相应ConfigVar进行更改,同时在fromstring()中用setValue进行更改存储时,会调用这一项配置参数已经注册的回调函数,从而使得配置真正生效。
ConfigVarBase::ptr Config::LookupBase(const std::string& name) {
// RWMutexType::ReadLock lock(GetMutex());
auto it = GetDatas().find(name);
return it == GetDatas().end() ? nullptr : it->second;
}
void Config::LoadFromYaml(const YAML::Node& root) {
std::list<std::pair<std::string, const YAML::Node> > all_nodes;
ListAllMember("", root, all_nodes);
std::cout<<"jiexidaxiao "<<all_nodes.size()<<std::endl;
for(auto& i : all_nodes) {
std::string key = i.first;
if(key.empty()) {
continue;
}
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
ConfigVarBase::ptr var = LookupBase(key);
std::cout<<key<<std::endl;
if(var) {
std::cout<<"yes11111i "<<key<<std::endl;
if(i.second.IsScalar()) {
std::cout<<"yes11311 "<<i.second.Scalar()<<std::endl;
var->fromString(i.second.Scalar());
} else {
std::cout<<"yes12111"<<std::endl;
std::stringstream ss;
ss << i.second;
std::cout<<"oooo"<<ss.str()<<std::endl;
var->fromString(ss.str());
}
}
}
}ListAllMember()函数在LoadFromYaml函数中进行调用,对Yml文件进行递归的解析,此处只对YAML::NodeType::MAP类型的YAML::Node进行递归处理,对于YAML::NodeType::Sequence不进行递归。
//"A.B", 10
//A:
// B: 10
// C: str
static void ListAllMember(const std::string& prefix,
const YAML::Node& node,
std::list<std::pair<std::string, const YAML::Node> >& output) {
if(prefix.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._012345678")
!= std::string::npos) {
SYLAR_LOG_ERROR(g_logger) << "Config invalid name: " << prefix << " : " << node;
return;
}
output.push_back(std::make_pair(prefix, node));
if(node.IsMap()) {
for(auto it = node.begin();
it != node.end(); ++it) {
ListAllMember(prefix.empty() ? it->first.Scalar()
: prefix + "." + it->first.Scalar(), it->second, output);
}
}
}
京公网安备 11010502036488号