Thrift自动生成代码处理层的实现做详细分析Word格式文档下载.docx
- 文档编号:22528740
- 上传时间:2023-02-04
- 格式:DOCX
- 页数:22
- 大小:56.97KB
Thrift自动生成代码处理层的实现做详细分析Word格式文档下载.docx
《Thrift自动生成代码处理层的实现做详细分析Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《Thrift自动生成代码处理层的实现做详细分析Word格式文档下载.docx(22页珍藏版)》请在冰豆网上搜索。
postRead
在读参数和处理函数之间调用
preWrite
在处理和写响应之间调用
postWrite
在写响应之后调用
asyncComplete
当一个异步函数成功完成调用时调用
handlerError
如果处理函数抛出没有定义的异常就会调用此函数
最后一个类就是TProcessorContextFreer类,这个类是一个帮助类,帮助生成的代码来释放上下文资源。
第二节
基于框架生成的服务实例分析
本节将对scribe服务器采用的服务实现进行详细分析。
1
接口定义语言文件(IDL)
(1)Facebook内部共用服务协议
主要有两个文件,一个是在Thrift中定义,是用于Facebook内部的一些接口服务定义,这个不仅仅用于scribe服务器,可能还用于Facebook内部其他系统,这个文件内容如下:
1namespacejavacom.facebook.fb303
2
3namespacecppfacebook.fb303
4
5namespaceperlFacebook.FB303
6
7enumfb_status{
8
9DEAD=0,
10
11STARTING=1,
12
13ALIVE=2,
14
15STOPPING=3,
16
17STOPPED=4,
18
19WARNING=5,
20
21}
22
23serviceFacebookService{
24
25stringgetName(),
26
27stringgetVersion(),
28
29fb_statusgetStatus(),
30
31stringgetStatusDetails(),
32
33map<
string,i64>
getCounters(),
34
35i64getCounter(1:
stringkey),
36
37voidsetOption(1:
stringkey,2:
stringvalue),
38
39stringgetOption(1:
40
41<
string,string>
getOptions(),
42
43stringgetCpuProfile(1:
i32profileDurationInSec),
44
45i64aliveSince(),
46
47onewayvoidreinitialize(),
48
49onewayvoidshutdown(),
50
51}
上面这个IDL文件定义了一个枚举类型用于表示服务的状态,还定义了一个名位FacebookService的服务,梦芭莎优惠券里面定义了各种操作,如获取服务状态的操作、得到计数的操作等等。
下面我们来看看根据这个IDL文件生成的C++代码是什么样的一个架构。
首先生成了一个基于上面服务定义的抽象类如下:
classFacebookServiceIf{
public:
virtual~FacebookServiceIf(){}
virtualvoidgetName(std:
string&
_return)=0;
virtualvoidgetVersion(std:
virtualfb_statusgetStatus()=0;
virtualvoidgetStatusDetails(std:
virtualvoidgetCounters(std:
map<
std:
string,int64_t>
&
virtualint64_tgetCounter(conststd:
key)=0;
virtualvoidsetOption(conststd:
key,conststd:
value)=0;
virtualvoidgetOption(std:
_return,conststd:
virtualvoidgetOptions(std:
:
string,std:
string>
virtualvoidgetCpuProfile(std:
_return,constint32_tprofileDurationInSec)=0;
virtualint64_taliveSince()=0;
virtualvoidreinitialize()=0;
virtualvoidshutdown()=0;
};
注意观察,除了这个类多了一个虚析构函数,其他函数就是IDL中定义的。
接着定义了类FacebookServiceNull,这个是上面那个抽象类的空实现(就是所有方法都没有做具体的事情),这样做的好处就是我们需要重写一些函数的时候只需要关注我们需要写的函数,而不是重写所有函数。
梦芭莎优惠券接着又定义了封装每一个函数参数的相应类,就是一个函数的参数都用一个类来封装定义,函数的返回值也是这样处理。
这样做的目的是统一远程调用的实现接口,因为传递参数都只需要这个封装类的对象就可以了。
所以你会看到每一个服务里面定义的函数都有下面一组类的定义:
1
(1)classFacebookService_getName_args{…}
3
(2)classFacebookService_getName_pargs{…}
5(3)typedefstruct_FacebookService_getName_result__isset{…}_FacebookService_getName_result__isset;
7(4)classFacebookService_getName_result{…}
9(5)typedefstruct_FacebookService_getName_presult__isset{…}_FacebookService_getName_presult__isset;
11(6)classFacebookService_getName_presult{…}
上面这六个类定义就是为服务中的getName函数服务的,相应的每一个函数都会有这种类似的定义和实现。
接下来就会定义三个具体实现IDL定义的功能的类,一个客户端的类,它继承定义的服务抽象类,每一个具体的函数实现都是同样的方式和思路,同样我结合getName函数的实现来看看这个过程,其他函数都是这样实现的,代码如下:
1send_getName();
3recv_getName(_return);
由上面代码可以看出首先调用函数发送函数名称及相关信息到远程,然后接受函数调用的返回值,发送函数send_getName()的代码如下:
1int32_tcseqid=0;
3oprot_->
writeMessageBegin("
getName"
:
apache:
thrift:
T_CALL,cseqid);
//写一个函数调用消息RPC
5FacebookService_getName_pargsargs;
7args.write(oprot_);
//写入参数
9oprot_->
writeMessageEnd();
11oprot_->
getTransport()->
writeEnd();
13oprot_->
flush();
//保证这次写入过程立即生效
上面代码就完成了函数名称以及参数的传输,调用的是TProtocol相关的类的函数实现,具体的实现内容和方式会在TProtocol部分介绍。
下面接着看一下接收返回值的函数recv_getName的代码:
1int32_trseqid=0;
//接收的消息序列号
3std:
stringfname;
//函数名称
5:
TMessageTypemtype;
//消息的类型(调用(T_CALL)、异常(T_EXCEPTION)等)
7iprot_->
readMessageBegin(fname,mtype,rseqid);
//从返回消息读取函数名称、消息类型
9if(mtype==:
T_EXCEPTION){//处理异常消息
11:
TApplicationExceptionx;
13x.read(iprot_);
15iprot_->
readMessageEnd();
17iprot_->
readEnd();
19throwx;
21}
23if(mtype!
=:
T_REPLY){//处理返回消息
25iprot_->
skip(:
T_STRUCT);
27iprot_->
29iprot_->
31}
33if(pare("
)!
=0){//看是否是我们需要的函数名,不是就跳过消息读取
35iprot_->
37iprot_->
39iprot_->
41}
43FacebookService_getName_presultresult;
45result.success=&
_return;
47result.read(iprot_);
//读取函数返回值
49iprot_->
51iprot_->
52
53if(result.__isset.success){//成功就返回结果(已经在_return里面),否则抛出异常
54
55return;
56
57}
58
59throw:
TApplicationException(:
TApplicationException:
MISSING_RESULT,"
getNamefailed:
unknownresult"
);
上面代码就是处理远程调用的返回结果,代码里面有注释。
一个服务函数的实现大概流程已经展现在我们面前了,处理的过程也已经清晰。
这个只是用于客户端的处理流程,必须通过有效的机制来通知服务器端调用相应的函数(这就是RPC)在服务器端完成相应功能并将结果返回。
这种机制就是通过我们这部分介绍的TProcessor类实现,这就是上面提到三个类中的第二个类,在这个实例中是FacebookServiceProcessor类,它从TProcessor类继承,重点实现两个函数process和process_fn,其中process会调用process_fn函数来处理客户端具体调用的那个服务函数,process函数定义如下:
1boolFacebookServiceProcessor:
process(boost:
piprot,
3boost:
poprot,void*callContext){
TProtocol*iprot=piprot.get();
7:
TProtocol*oprot=poprot.get();
9std:
11:
13int32_tseqid;
15iprot->
readMessageBegin(fname,mtype,seqid);
//读取得到函数名称、消息类型和函数序列号
17//处理不是函数调用消息的情况
19if(mtype!
T_CALL&
&
mtype!
T_ONEWAY){
21iprot->
23iprot->
25iprot->
27:
TApplicationExceptionx(:
INVALID_MESSAGE_TYPE);
29//写入(返回)一个异常信息给调用客户端,客户端会根据返回结果处理异常
31oprot->
writeMessageBegin(fname,:
T_EXCEPTION,seqid);
33x.write(oprot);
35oprot->
37oprot->
39oprot->
41returntrue;
43}
45returnprocess_fn(iprot,oprot,fname,seqid,callContext);
//调用实际的函数处理
47}
上面代码有比较详细的注释,还需要说明一点的就是如果传递的不是函数调用的消息类型就会返回给客户端一个异常的消息,客户端的接收返回值的函数就会根据收到的异常消息做相应处理,上面getName函数的接收返回值函数就是抛出一个服务器端给的异常信息。
下面继续看最终服务器端调用相应映射函数的处理,这个是通过process_fn函数实现:
具体定义如下:
process_fn(:
TProtocol*iprot,
3:
TProtocol*oprot,std:
fname,int32_tseqid,void*callContext){
5//定义个map的迭代器,用于接收在函数映射查找到的映射函数
7std:
string,void(FacebookServiceProcessor:
*)(int32_t,:
TProtocol*,
9:
TProtocol*,void*)>
iteratorpfn;
11pfn=processMap_.find(fname);
//根据函数名称查找对应的映射处理函数
13if(pfn==processMap_.end()){//如果没有找到,做下面的处理
17iprot->
19iprot->
21//抛出一个不知道的方法的异常
23:
UNKNOWN_METHOD,
25"
Invalidmethodname:
'
"
+fname+"
'
27//写入到调用客户端
29oprot->
31x.write(oprot);
33oprot->
39returntrue;
43(this->
*(pfn->
second))(seqid,iprot,oprot,callContext);
//调用具体的函数(RPC过程完成)
45returntrue;
上面这个函数最终完成了RPC的过程,那个函数与映射函数的对应关系的map结构是在构造函数中初始化的,所以可以找到,例如我们举例的getName函数是下面这样初始化的:
1processMap_["
]=&
FacebookServiceProcessor:
process_getName;
和getName函数一样,对于IDL定义的每一个函数在FacebookServiceProcessor类中都有一个映射的处理函数,为了展示一个完整的处理过程我们在看看getName函数的映射处理函数process_getName,它的定义如下:
1voidFacebookServiceProcessor:
process_getName(int32_tseqid,
TProtocol*iprot,:
TProtocol*oprot,void*callContext)
5{
7void*ctx=NULL;
9if(eventHandler_.get()!
=NULL){
11//得到上下文调用环境
13ctx=eventHandler_->
getContext("
FacebookService.getName"
callContext);
15}
17//定义并初始化一个用于释放资源的帮助类对象
19:
TProcessorContextFreerfreer(eventHandler_.get(),
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Thrift 自动 生成 代码 处理 实现 详细 分析
![提示](https://static.bdocx.com/images/bang_tan.gif)