相关动态
做seo营销网站/百度惠生活商家入驻
2024-12-21 17:17

假定我们定义了一个Persion的message type,我们的用法可能如下

定义 和 

package tutorial;
message Person {required int32 id = 1;optional string name = 2;optional string email = 3;
}

编写自己的代码进行数据的填充和序列化,并引入

Person person;
person.set_id(1234);
person.set_name("John Doe");
person.set_email("jdoe@");
string output;
person.SerializeToString(&output);

 

假设我们的系统应用场景是:数据都是持久化在mysql中,同时提供memcached作为缓存。在使用中通常缓存miss后会从mysql中读取数据后进行序列化并set到memcached中再返回给用户。

 

还是以上面的message type为例,在mysql中还有一张表持久化存储了对应的数据。我们把mysql定义的数据的属性名跟proto定义的属性名都是一样的。现在我们想把mysql中读出来的某条记录(mysqlpp::Row)转换成对应的protobuf的消息

Create table Person {id int(11) not null,name varchar(64),emal varchar(255),........
}

如果我们想把数据库读出来的一条记录进行序列化,需要先转换成protobuf定义的Message,然后调用Message的SerializeToString进行序列化

我们的转换函数可能是这么写的

void fill(mysqlpp::Row& row, tutorial::Person&  persion){persion.set_id((int)row[“id”]);persion.set_name((std::string)row[“name”]);persion.set_email((std::string)row[“email”]);
}

这种方法要求我们针对一个新来的message type就需要新写一段这样的代码。如果我们的系统支撑了很多不同的消息类型,每个消息类型的名称,参数个数,名称以及类型都不同。在填充数据的时候针对每个类型都需要写类似的代码,必然会制约我们系统的扩展性和维护性。幸好protobuf提供了反射的机制,给我们提供了更多发挥想象力的空间。

 

所有的message type(比如tutorial::Persion)都是继承自Message class。

Message class 定义了 New() 虚函数,用以返回本对象的一份新实例,类型与本对象的真实类型相同。也就是说,拿到 Message* 指针,不用知道它的具体类型,就能创建和它类型一样的具体 Message Type 的对象。

Message class 定义了GetReflection虚函数,可以返回一个Reflection对象,这个对象可以动态的访问和修改message里面的field内容

每个Message Type对应一个Descriptor对象,通过这个对象我们可以在运行时得到Message Type包含的field,以及field的类型描述。

那我们如何拿到一个Message Type对应的Message* 指针了

//在上面的例子中使用, typeName = "tutorial::Persion"
Message* createMessage(const std::string& typeName)
{Message* message = NULL;const Descriptor* descriptor = DescriptorPool::generated_pool()->FindMessageTypeByName(typeName);if (descriptor){const Message* prototype = MessageFactory::generated_factory()->GetPrototype(descriptor);if (prototype){message = prototype->New();}}return message;
}

这样我们就可以根据Message Type的名字获取到对应的Message* 指针

那又如何动态的把mysql中的数据填充进去了

 

void convert(const mysqlpp::Row& row, std::string& data){Message* message = createMessage(message_type);const Reflection* reflection = message->GetReflection();const Descriptor* descriptor = message->GetDescriptor();for(int i=0; i < descriptor->field_count(); ++i){reflectionFill(message,descriptor->field(i),reflection,row);}message->SerializeToString(&data);delete message;
}
void reflectionFill(Message* message, const FieldDescriptor* descriptor, const Reflection* reflection, const mysqlpp::Row& row){assert(descriptor != NULL);//current not support for repeated labelif(descriptor->label() == FieldDescriptor::LABEL_REPEATED){return;}const char* name = descriptor->name().c_str();switch(descriptor->type()){case FieldDescriptor::TYPE_FIXED64 :case FieldDescriptor::TYPE_INT64 :reflection->SetInt64(message,descriptor,(long long)row[name]);break;case FieldDescriptor::TYPE_UINT64 :reflection->SetInt64(message,descriptor,(unsigned long long)row[name]);break;case FieldDescriptor::TYPE_FIXED32:case FieldDescriptor::TYPE_INT32 :reflection->SetInt32(message,descriptor,(int)row[name]);break;case FieldDescriptor::TYPE_UINT32 :reflection->SetInt32(message,descriptor,(unsigned int)row[name]);break;case FieldDescriptor::TYPE_STRING :reflection->SetString(message,descriptor,(std::string)row[name]);break;case FieldDescriptor::TYPE_DOUBLE :reflection->SetDouble(message,descriptor,(double)row[name]);break;case FieldDescriptor::TYPE_FLOAT :reflection->SetFloat(message,descriptor,(float)row[name]);break;case FieldDescriptor::TYPE_BOOL :reflection->SetBool(message,descriptor,(bool)row[name]);break;default : std::cerr << "not support type " << descriptor->type() << std::endl;}
}

这种方式要求我们必须在编译的时候就把对应的  生成的 和 的时候每次都需要重新编译。

不过protobuf提供了动态编译的功能,让我们在程序运行期也可以动态的编译 class。

class MockErrorCollector : public MultiFileErrorCollector {public:MockErrorCollector() {}~MockErrorCollector() {}std::string text_;// implements ErrorCollector ---------------------------------------void AddError(const std::string& filename, int line, int column,const std::string& message) {std::cerr << "error filename "<<filename <<" message "<<message <<std::endl;}
};
MockErrorCollector errorCollector;
google::protobuf::compiler::DiskSourceTree sourceTree;
google::protobuf::compiler::importer importer(&sourceTree, &errorCollector);
sourceTree.MapPath("", "http://www.nhpp.cn/news/");
importer.import("");

使用这种方式可以在运行期动态编译新添加proto,不过Message*的获取稍有不同,是因为之前的获取方式只能用于编译期添加的Message class

需要使用进行如下的修改

    以上就是本篇文章【做seo营销网站/百度惠生活商家入驻】的全部内容了,欢迎阅览 ! 文章地址:http://sjzytwl.xhstdz.com/news/12049.html 
     栏目首页      相关文章      动态      同类文章      热门文章      网站地图      返回首页 物流园资讯移动站 http://sjzytwl.xhstdz.com/mobile/ , 查看更多   
最新文章
苹果手机开不开机如何解决,苹果手机开不开机是咋回事苹果手机如何开机「苹果手机开不开机如何解决,苹果手机开不开机是咋回事」
苹果手机开不开机怎么办苹果手机开不了机这种情况,还有可能是手机处于死机状态,也可以先尝试一下同时按住开机键开机键+HOME键
这么多年过去了,米家为啥还不能实现离线操作?小米手机闹钟在哪里设置「这么多年过去了,米家为啥还不能实现离线操作?」
这么多年过去了,米家为啥还不能实现离线操作?“ 小爱同学,打开空调 ”“ 小爱同学!,打开空调 ”“ 小爱同学???? ”这么
手机上的这些隐形参数 厂商可能不会告诉你隐形手机「手机上的这些隐形参数 厂商可能不会告诉你」
在文章正式开始之前,先问大家伙儿一个问题:在挑手机的时候,不知道各位主要会看哪些参数?像是芯片、屏幕、影像、内存、存储、
山西一男子高速上边开车边玩手机游戏被处罚开车玩手机「山西一男子高速上边开车边玩手机游戏被处罚」
  这名司机心真大!山西一男子高速上边开车边玩手机游戏被处罚   新华社太原11月26日电(记者王飞航)究竟是命重要,还是玩游
米忽悠派对最新版本 v1.0手机版派对手机「米忽悠派对最新版本 v1.0手机版」
米忽悠派对是一款以米哈游的游戏ip打造的全新派对游戏,在游戏中能够看到许多米哈游的不同游戏集合在一个游戏中,游戏玩法十分简
油电同智 全球同行,奇瑞汽车智能化战略发布会盛大开幕
3月18日,智能化战略发布会在安徽芜湖顺利召开。活动聚焦“油电同智 全球同行”,正式发布奇瑞集团智能化战略规划,并集中展示猎
投影仪如何通过手机投屏-实用教程手机怎么投屏到投影仪「投影仪如何通过手机投屏-实用教程」
第二步:开启手机投屏功能打开手机上的设置或者控制中心(不同手机可能位置不同),找到“投屏”或者“无线投屏”这样的选项并点
才发现手机蓝牙竟然有这么神奇的功能,你们都知道手机蓝牙的哪些作用呢?手机蓝牙有什么作用「才发现手机蓝牙竟然有这么神奇的功能,你们都知道手机蓝牙的哪些作用呢?」
提到手机蓝牙,大家能想到的它的功能是什么呢?不少人可能对手机蓝牙的作用还停留在以前,两个手机配对之后可以用来传输文件,这
全球最火的十大射击游戏推荐 好玩的射击游戏前十2023手机最真实的射击游戏「全球最火的十大射击游戏推荐 好玩的射击游戏前十2023」
现在手机上的射击游戏种类是很丰富的,不同题材的射击游戏给大家提供了不同的体验,射击游戏里的众多枪械可谓开拓了大家的眼界,
苹果发布iPhone8和iPhoneX 后者系第一代价格十倍苹果x手机多少钱「苹果发布iPhone8和iPhoneX 后者系第一代价格十倍」
  在苹果手机面世10周年之际,苹果公司12日发布iPhone 8和iPhone X等最新产品,以此向已故联合创始人史蒂夫?乔布斯致敬。  

loading