一、什么是thrift
Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由FaceBook为“大规模跨语言服务开发”而开发的。它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的、无缝的跨平台高效服。后来捐献给apache组织了。
二、thrift的架构
Thrift包含一套完整的栈来创建客户端和服务端程序。顶层部分是由Thrift定义生成的代码。而服务则由这个文件客户端和处理器代码生成。在生成的代码里会创建不同于内建类型的数据结构,并将其作为结果发送。协议和传输层是运行时库的一部分。有了Thrift,就可以定义一个服务或改变通讯和传输协议,而无需重新编译代码。除了客户端部分之外,Thrift还包括服务器基础设施来集成协议和传输,如阻塞、非阻塞及多线程服务器。栈中作为I/O基础的部分对于不同的语言则有不同的实现。
Thrift支持众多通讯协议:
-
TBinaryProtocol – 一种简单的二进制格式,简单,但没有为空间效率而优化。比文本协议处理起来更快,但更难于调试。
-
TCompactProtocol – 更紧凑的二进制格式,处理起来通常同样高效。
-
TDebugProtocol – 一种人类可读的文本格式,用来协助调试。
-
TDenseProtocol – 与TCompactProtocol类似,将传输数据的元信息剥离。
-
TJSONProtocol – 使用JSON对数据编码。
-
TSimpleJSONProtocol – 一种只写协议,它不能被Thrift解析,因为它使用JSON时丢弃了元数据。适合用脚本语言来解析。
支持的传输协议有:
-
TFileTransport – 该传输协议会写文件。
-
TFramedTransport – 当使用一个非阻塞服务器时,要求使用这个传输协议。它按帧来发送数据,其中每一帧的开头是长度信息。
-
TMemoryTransport – 使用存储器映射输入输出。(Java的实现使用了一个简单的ByteArrayOutputStream。)
-
TSocket – 使用阻塞的套接字I/O来传输。
-
TZlibTransport – 用Zlib执行压缩。用于连接另一个传输协议。
Thrift还提供众多的服务器,包括:
-
TNonblockingServer – 一个多线程服务器,它使用非阻塞I/O(Java的实现使用了NIO通道)。TFramedTransport必须跟这个服务器配套使用。
-
TSimpleServer – 一个单线程服务器,它使用标准的阻塞I/O。测试时很有用。
-
TThreadPoolServer – 一个多线程服务器,它使用标准的阻塞I/O。
三、thrift的使用
1.下载并安装thrift.exe,然后配置环境变量,使用thrift -version 来验证是否安装成功
2.编写.thrift文件
//名称空间,用来隔离代码,防止数据类型定义中名字冲突 namespace java netty_thrift //引入其他thrift文件 //include "test.thrift" /** 数据类型定义,通过typedef将thrift中的类型和java中的类型对应起来,然后直接使用java中的数据类型,方便理解 下面就是thrift中使用的基本数据类型 */ typedef i16 short typedef i32 int typedef i64 long typedef bool boolean typedef string String typedef double double //定义常量 //const int CONSTANT_A = 12345 /** 定义结构 1.每个属性都有唯一一个正整数标识符 2.每个属性都可以标记为optional和required 3.每个结构体都可以包含其他结构体 4.每个属性都有默认值 5. */ struct Person{ 1: optional String username 2: optional int age 3: optional boolean married } //异常定义 exception DataException{ 1: optional String message 2: optional String callStack 3: optional String date } //服务定义 service PersonService{ Person getPersonByName(1: required String username) throws (1: DataException dataException), void savePerson(1: required Person person) }
enum TweetType {//仅仅是作为一个例子,后面生成代码时没有用到
TWEET, // 编译器默认从1开始赋值
RETWEET = 2, // 可以赋予某个常量某个整数
DM = 0xa, //允许常量是十六进制整数
REPLY // 末尾没有逗号
}
3.生成java代码
使用命令行thrift -gen java D:WorkSpace1 ettysrc etty_thriftdata.thrift 生成的文件在执行命令时所在的目录。
4.编写服务端和客户端的代码
public class Server { public static void main(String[] args) throws TTransportException { TNonblockingServerSocket socket = new TNonblockingServerSocket(9999); org.apache.thrift.server.THsHaServer.Args args3 = new THsHaServer.Args(socket); Processor<PersonServiceImpl> processor = new PersonService.Processor<>(new PersonServiceImpl()); args3.protocolFactory(new TCompactProtocol.Factory()); args3.transportFactory(new TFramedTransport.Factory()); args3.processorFactory(new TProcessorFactory(processor)); THsHaServer server = new THsHaServer(args3); server.serve(); } }
public class PersonServiceImpl implements PersonService.Iface { @Override public Person getPersonByName(String username) throws DataException, TException { Person p = new Person(); p.setUsername(username); p.setAge(28); p.setMarried(false); return p; } @Override public void savePerson(Person person) throws TException { System.out.println(person); } }
public class Client { public static void main(String[] args) throws DataException, TException { TFramedTransport tFramedTransport = new TFramedTransport(new TSocket("localhost",9999)); TProtocol protocol = new TCompactProtocol(tFramedTransport); netty_thrift.PersonService.Client client = new PersonService.Client(protocol); tFramedTransport.open(); Person person = client.getPersonByName("kyle"); System.out.println(person); Person p = new Person(); p.setUsername("xiaoming"); p.setAge(24); p.setMarried(false); client.savePerson(p); } }