thrift是一套远程调用框架,最初是由Facebook开发的,并在2008年捐给了Apache基金会,成为了一个孵化器项目。thrift支持可扩展且跨语言的服务的开发,它结合了功能强大的软件堆栈和代码生成引擎,支持的客户端语言包括C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 。
Thrift的设计提供了以下这些特性:
1、语言无关的类型
因为类型是使用定义文件按照语言中立的方式规定的,所以它们可以被不同的语言分析。比如,C++的结构可以和Python的字典类型相互交换数据。
2、通用传输接口
不论你使用的是磁盘文件、内存数据还是socket流,都可以使用同一段应用代码。
3、协议无关
Thrift会对数据类型进行编码和解码,可以跨协议使用。
4、支持版本
数据类型可以加入版本信息,来支持客户端API的更新。
thrift安装
对于mac用户来说,brew是个很好用的命令,使用命令快速安装thrift。
admindeMacBook-Pro-5:~ hzjdemac$ brew install thrift
==> Installing dependencies for thrift: boost
==> Installing thrift dependency: boost
==> Downloading https://homebrew.bintray.com/bottles/boost-1.68.0.high_sierra.bottle.tar.gz
######################################################################## 100.0%
==> Pouring boost-1.68.0.high_sierra.bottle.tar.gz
🍺 /usr/local/Cellar/boost/1.68.0: 13,712 files, 460.2MB
==> Installing thrift
==> Downloading https://homebrew.bintray.com/bottles/thrift-0.11.0.high_sierra.bottle.tar.gz
######################################################################## 100.0%
==> Pouring thrift-0.11.0.high_sierra.bottle.tar.gz
==> Caveats
To install Ruby binding:
gem install thrift
==> Summary
🍺 /usr/local/Cellar/thrift/0.11.0: 102 files, 7MB
==> Caveats
==> thrift
To install Ruby binding:
gem install thrift
admindeMacBook-Pro-5:~ hzjdemac$ thrift
Usage: thrift [options] file
Use thrift -help for a list of options
admindeMacBook-Pro-5:~ hzjdemac$ thrift -version
Thrift version 0.11.0
数据类型
java中定义一个接口需要传入参数,方法名,返回值和抛异常操作,这其中比较关键的是参数。thrift自己内部有一套与语言无关的类型,可以与java中的类型进行对应,将java中的类型换成thrift对应的类型就能够将java接口定义转换成thrift接口定义。
类型 | 解释 | java对应类型 | C++对应类型 |
---|---|---|---|
bool | 布尔值,true 或 false | boolean | bool |
byte | 8 位有符号整数 | byte | int |
i16 | 16 位有符号整数 | short | int |
i32 | 32 位有符号整数 | int | int |
i64 | 64 位有符号整数 | long | long |
double | 64 位浮点数 | double | double |
string | utf-8编码的字符串 | String | string |
list<t> | 元素类型为t的有序表,容许元素重复 | ArrayList | vector |
set<t> | 元素类型为t的无序表,不容许元素重复 | HashSet | set |
map<k,t> | 键类型为t,值类型为t的kv对,键不容许重复 | HashMap | map |
struct | 一组对象 | class | struct |
exception | 异常 | Exception | Exception |
service | 服务类型 | interface | 抽象类 |
enum | 枚举 | enum | enum |
namespace:熟悉C++的朋友肯定知道,提供了一种组织(隔离)代码的简便方式,类似于C++中的namespace和JAVA中的package。
include:包含其它thrift文件,功能类似于C++中的include和JAVA中的import。
thrift中struct是定义为一种对象,和面向对象语言的class差不多.,但是struct有以下一些约束:
struct不能继承,但是可以嵌套,不能嵌套自己。
其成员都是有明确类型
成员是被正整数编号过的,其中的编号使不能重复的,这个是为了在传输过程中编码使用。
成员分割符可以是逗号(,)或是分号(;),而且可以混用,但是为了清晰期间,建议在定义中只使用一种,比如C++学习者可以就使用分号(;)。
字段会有optional和required之分和protobuf一样,但是如果不指定则为无类型—可以不填充该值,但是在序列化传输的时候也会序列化进去,optional是不填充则部序列化,required是必须填充也必须序列化。
每个字段可以设置默认值
同一文件可以定义多个struct,也可以定义在不同的文件,进行include引入。
下面将举一个例子,该例子用thrift定义了一个接口,基本囊括了类型定义和方法定义的基本用法。
样例
enum EnOpType {
CMD_OK = 0, // (0)
CMD_NOT_EXIT = 2000, // (2000)
CMD_EXIT = 2001, // (2001)
CMD_ADD = 2002 // (2002)
}
struct UserProfile {
1: i32 uid = 1,
2: string name = "User1",
3: string blurb
}
include "UserProfile.thrift"
include "EnOpType.thrift"
struct Node {
1: i32 id,
2: string name,
3: EnOpType.EnOpType enOpType;
4: list<UserProfile.UserProfile> subNodeList
}
exception CommonException {
1: i32 errorCode,
2: string message
}
include "Node.thrift"
include "UserProfile.thrift"
include "exception.thrift"
service UserStorage {
void store(1:UserProfile.UserProfile user) throws (1:exception.CommonException commonException);
Node.Node retrieve(1:i32 uid) throws (1:exception.CommonException commonException);
}
最后对每个文件使用thrift命令生成指定语言的文件, 使用ls可以查看到所有的文件,打开UserStorage.java文件,可以清楚得看到生成的java接口。
admindeMacBook-Pro-5:~ hzjdemac$ thrift -r -gen java UserStorage.thrift
admindeMacBook-Pro-5:~ hzjdemac$ cd gen-java
admindeMacBook-Pro-5:gen-java hzjdemac$ ls
CommonException.java EnOpType.thrift Node.thrift UserProfile.thrift UserStorage.thrift model.thrift
EnOpType.java Node.java UserProfile.java UserStorage.java exception.thrift
admindeMacBook-Pro-5:gen-java hzjdemac$ vim UserStorage.java
/**
* Autogenerated by Thrift Compiler (0.11.0)
*
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
* @generated
*/
@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.11.0)", date = "2018-11-25")
public class UserStorage {
public interface Iface {
public void store(UserProfile user) throws CommonException, org.apache.thrift.TException;
public Node retrieve(int uid) throws CommonException, org.apache.thrift.TException;
}
public interface AsyncIface {
public void store(UserProfile user, org.apache.thrift.async.AsyncMethodCallback<Void> resultHandler) throws org.apache.thrift.TException;
public void retrieve(int uid, org.apache.thrift.async.AsyncMethodCallback<Node> resultHandler) throws org.apache.thrift.TException;
}
public static class Client extends org.apache.thrift.TServiceClient implements Iface {
public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {
public Factory() {}
public Client getClient(org.apache.thrift.protocol.TProtocol prot) {
return new Client(prot);
}
public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
return new Client(iprot, oprot);
}
}
public Client(org.apache.thrift.protocol.TProtocol prot)
{
super(prot, prot);
}
public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
super(iprot, oprot);
}
public void store(UserProfile user) throws CommonException, org.apache.thrift.TException
{
send_store(user);
recv_store();
}
好了,本节主要讲解了如何将一个定义thrift service,生成了java中的接口,很可惜的地方是不支持泛型。下篇将讲解客户端和服务端的rpc通信。
参考资料:
1.https://www.cnblogs.com/duanxz/p/5516558.html
2.https://www.cnblogs.com/valor-xh/p/6386584.html