Thrift之TProtocol类体系原理及源码详细解析之类继承架构分析

本文主要是介绍Thrift之TProtocol类体系原理及源码详细解析之类继承架构分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://blog.csdn.net/wanweiaiaqiang/article/details/7632665



这部分相关的类主要实现与协议相关的内容,这里说的协议是指对数据传输格式封装的协议,实现不同的协议来适合不同场景下的数据传输,因为在不同的场景下不同协议对于数据传输来说效率有很大的差别。下面是这个部分相关类的类关系图:


由以上类图可以发现所有的协议类都从TProtocol类直接或间接继承,每一个协议类都有一个对应的生产对象工厂(协议工厂)。TProtocol是一个抽象的类,不能直接使用的,它有一个直接子类默认实现了所有方法(空实现),如果我们需要定义自己的数据传输协议可以直接从这个类继承。

第一节 类继承架构分析

为什么需要对这部分的类继承架构进行分析了?上面不是有很清楚的类继承关系图了吗?但是Facebook在实现时并不是简单的这样继承下来就可以了,Facebook为了后期协议的可扩展性和允许其他组织、团队或个人实现自己的数据传输(主要是数据格式的封装)协议,里面多加了一层继承关系,就是类图中的TVirtualProtocol类,从类的名称可以看出这是一个虚的协议。怎样理解这个虚的协议了?通过阅读代码我觉得可以这样理解:因为它定义为一个模板类,这个模板类有两个参数,一个用于数据传输的真正协议,一个是用来继承的,它本身没有对协议具体内容做实现,所以说它是一个虚的协议类。下面我们对这个类继承架构结合代码实现来具体分析。

抽象类TProtocol和默认实现类TProtocolDefaults

抽象类对于每一种数据类型都提供了读写的开始和介绍的方法,这里读写方法应该是针对网络IO读写,不过真正实现网络读写还不是这里的方法,这里方法主要处理数据,例如对数据格式做调整。真正实现网络IO读写是下一章介绍的TTransport相关类实现的,那里还会对传输的方式做相应控制,例如是否压缩。

除了具体的数据类型有写入和读取的方法,消息也是需要通过网络传递,所以也定义了消息的传输读写方法。当然还定义了一些公用的功能,如跳过某一个结构不读、大小端数据格式调整、主机字节序和网络字节序的相互转换等。

1)首先定义纯虚函数:

virtual uint32_t writeMessageBegin_virt(const std::string& name,

                                  const TMessageType messageType,  const int32_t seqid) = 0;

  virtual uint32_t writeMessageEnd_virt() = 0;

  virtual uint32_t writeStructBegin_virt(const char* name) = 0;

  virtual uint32_t writeStructEnd_virt() = 0;

2)然后定义调用相应纯虚函数的函数:

 uint32_t writeMessageBegin(const std::string& name, const TMessageType messageType, const int32_t seqid) {

    T_VIRTUAL_CALL();//打印调用日志函数

    return writeMessageBegin_virt(name, messageType, seqid);

  }

  uint32_t writeMessageEnd() {

    T_VIRTUAL_CALL();

    return writeMessageEnd_virt();

  }

  uint32_t writeStructBegin(const char* name) {//写结构体开始

    T_VIRTUAL_CALL();

    return writeStructBegin_virt(name);

  }

  uint32_t writeStructEnd() {//写结构体结束

    T_VIRTUAL_CALL();

    return writeStructEnd_virt();

  }

3)其他公共函数

  uint32_t skip(TType type) {

    T_VIRTUAL_CALL();

    return skip_virt(type);//跳过数据类型

  }

  virtual uint32_t skip_virt(TType type) {

    return ::apache::thrift::protocol::skip(*this, type);// 调用此命名空间下全局函数实现

  }

4)全局数据结构定义

enum TType {//Thrift协议支持的数据类型枚举定义

  T_STOP       = 0,

  T_VOID       = 1,

  T_BOOL       = 2,

  T_BYTE       = 3,

  T_I08        = 3,

  T_I16        = 6,

  T_I32        = 8,

  T_U64        = 9,

  T_I64        = 10,

  T_DOUBLE     = 4,

  T_STRING     = 11,

  T_UTF7       = 11,

  T_STRUCT     = 12,

  T_MAP        = 13,

  T_SET        = 14,

  T_LIST       = 15,

  T_UTF8       = 16,

  T_UTF16      = 17

};

enum TMessageType {//thrift支持的消息类型

  T_CALL       = 1,

  T_REPLY      = 2,

  T_EXCEPTION  = 3,

  T_ONEWAY     = 4//函数的异步调用方式

};

还定义了一个对应抽象工厂类,用于上产具体的协议对象,这就是设计模式中最常用的抽象工厂设计模式。上面代码只是简单列举了两个写入的函数,还有其他很多相关数据类型的写入和读取函数因为都相同格式定义就没有具体拿出来说明了。

至于默认实现类TProtocolDefaults主要重写了抽象类TProtocol的非虚拟化的方法,这些方法都抛出一个方法为实现(TProtocolException::NOT_IMPLEMENTED)的异常。这样做的主要目的为了下面要讲到的类TVirtualProtocol提供默认的继承基类,从而防止无限递归调用。下面分析TVirtualProtocol类时具体分析如果没有这个默认实现类怎样产生无限递归调用。

虚协议类TVirtualProtocol

首先看看这个特殊的模板类是怎样定义的:

template <class Protocol_, class Super_=TProtocolDefaults>

class TVirtualProtocol : public Super_ { 

……//省略具体内容

}

说它特殊我觉得主要是基于两个方面:

1)继承的类可以通过模板参数传递,也就是说你现在没有办法肯定它现在带地继承什么类,只是默认参数值是我们上面介绍的抽象类的默认实现类。

2)类里面的方法实现全部是采用把this指针转换为第一个模板参数的类型然后调用模板参数类型的相关方法。如下面的一个方法的定义:

  virtual uint32_t writeMessageBegin_virt(const std::string& name,

                       const TMessageType messageType, const int32_t seqid) {

    return static_cast<Protocol_*>(this)->writeMessageBegin(name, messageType, seqid);

  }//实现抽象类的writeMessageBegin_virt方法

由上面两个特点可以发现这个类只是提供一个空的架构壳,继承的类可以指定,当然也可以采用默认的,后面分析具体协议实现的时候可以发现大多数协议也确实是采用默认的继承类,且大多数继承这个虚协议的类都是传递第一个参数为自身,也就是调用自己定义的相应函数。如TBinaryProtocolT类的定义,如下:

template <class Transport_>

class TBinaryProtocolT : public TVirtualProtocol< TBinaryProtocolT<Transport_> > {

…….

}

下面来分析如果不从定义的默认实现类继承,直接从抽象类继承怎样会产生无限递归调用。现在我们假设直接从抽象类继承,那么如果一个指向子类对象的父类(TProtocol)调用writeMessageBegin方法,因为这个方法不是虚拟函数(不会动态绑定)所以就会调用父类的writeMessageBegin方法,然后父类会直接调用它的纯虚函数writeMessageBegin_virt,这个函数就会动态绑定,就会执行子类的实现,在这里就是通过虚协议类TVirtualProtocol实现的,而这个函数又会调用之类的writeMessageBegin方法,如果子类没有实现这个方法,那么就又回到父类的这个方法了,从而产生无限递归调用。那么如果默认是从默认实现类TProtocolDefaults继承,那么就会执行它的writeMessageBegin方法,从而抛出一个异常,就不会产生无限递归调用。

具体协议类或实现自己的协议类

这个就是类继承架构的最后一部分,也就是实现具体的数据传输协议。例如二进制协议类定义如下:

template <class Transport_>

class TBinaryProtocolT : public TVirtualProtocol< TBinaryProtocolT<Transport_> > { …… }

那么这个二进制协议类就不用实现那些虚拟方法了。那些具体的协议实现方式后面详细介绍。

现在对这部分的类继承架构已经分析完毕,后面开始介绍Thrift中实现的几个比较重要的协议。



这篇关于Thrift之TProtocol类体系原理及源码详细解析之类继承架构分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/810970

相关文章

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Linux中shell解析脚本的通配符、元字符、转义符说明

《Linux中shell解析脚本的通配符、元字符、转义符说明》:本文主要介绍shell通配符、元字符、转义符以及shell解析脚本的过程,通配符用于路径扩展,元字符用于多命令分割,转义符用于将特殊... 目录一、linux shell通配符(wildcard)二、shell元字符(特殊字符 Meta)三、s

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Java操作PDF文件实现签订电子合同详细教程

《Java操作PDF文件实现签订电子合同详细教程》:本文主要介绍如何在PDF中加入电子签章与电子签名的过程,包括编写Word文件、生成PDF、为PDF格式做表单、为表单赋值、生成文档以及上传到OB... 目录前言:先看效果:1.编写word文件1.2然后生成PDF格式进行保存1.3我这里是将文件保存到本地后

windows系统下shutdown重启关机命令超详细教程

《windows系统下shutdown重启关机命令超详细教程》shutdown命令是一个强大的工具,允许你通过命令行快速完成关机、重启或注销操作,本文将为你详细解析shutdown命令的使用方法,并提... 目录一、shutdown 命令简介二、shutdown 命令的基本用法三、远程关机与重启四、实际应用

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

使用Python实现批量访问URL并解析XML响应功能

《使用Python实现批量访问URL并解析XML响应功能》在现代Web开发和数据抓取中,批量访问URL并解析响应内容是一个常见的需求,本文将详细介绍如何使用Python实现批量访问URL并解析XML响... 目录引言1. 背景与需求2. 工具方法实现2.1 单URL访问与解析代码实现代码说明2.2 示例调用

使用SpringBoot创建一个RESTful API的详细步骤

《使用SpringBoot创建一个RESTfulAPI的详细步骤》使用Java的SpringBoot创建RESTfulAPI可以满足多种开发场景,它提供了快速开发、易于配置、可扩展、可维护的优点,尤... 目录一、创建 Spring Boot 项目二、创建控制器类(Controller Class)三、运行

springboot整合gateway的详细过程

《springboot整合gateway的详细过程》本文介绍了如何配置和使用SpringCloudGateway构建一个API网关,通过实例代码介绍了springboot整合gateway的过程,需要... 目录1. 添加依赖2. 配置网关路由3. 启用Eureka客户端(可选)4. 创建主应用类5. 自定

SSID究竟是什么? WiFi网络名称及工作方式解析

《SSID究竟是什么?WiFi网络名称及工作方式解析》SID可以看作是无线网络的名称,类似于有线网络中的网络名称或者路由器的名称,在无线网络中,设备通过SSID来识别和连接到特定的无线网络... 当提到 Wi-Fi 网络时,就避不开「SSID」这个术语。简单来说,SSID 就是 Wi-Fi 网络的名称。比如