Thrift 入门指南

来源:互联网 发布:3dmax unity3d 编辑:程序博客网 时间:2024/06/01 03:58

一、内容概要
          Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。         
          上一篇文章着重讲解关于thrift框架的介绍。本文主要讲述的对象是thrift文件,及其client和server的编写方法。

二、Thrift语法
1. Thrift类型

Thrift类型系统包括预定义基本类型,用户自定义结构体,容器类型,异常和服务定义
(1) 基本类型

<span style="font-size:14px;">bool:布尔类型(true or value),占一个字节 byte:有符号字节 i16:16位有符号整型 i32:32位有符号整型 i64:64位有符号整型 double:64位浮点数 string:未知编码或者二进制的字符串</span>

注意,thrift不支持无符号整型,因为很多目标语言不存在无符号整型(如java)。
(2) 容器类型
Thrift容器与类型密切相关,它与当前流行编程语言提供的容器类型相对应,采用java泛型风格表示的。Thrift提供了3种容器类型:
list<t1>:一系列t1类型的元素组成的有序表,元素可以重复。相当于Java中的List
set<t1>:一系列t1类型的元素组成的无序表,元素唯一。相当于Java中的Set
map<t1,t2>:key/value对(key的类型是t1且key唯一,value类型是t2)。相当于Java中的Map
容器中的元素类型可以是除了service意外的任何合法thrift类型(包括结构体和异常)。
(3)  结构体和异常
Thrift结构体在概念上同C语言结构体类型—-一种将相关属性聚集(封装)在一起的方式。在面向对象语言中,thrift结构体被转换成类。结构体使用struct关键字声明。
异常在语法和功能上类似于结构体,只不过异常使用关键字exception而不是struct关键字声明。但它在语义上不同于结构体—当定义一个RPC服务时,开发者可能需要声明一个远程方法抛出一个异常。
结构体和异常的声明将在下一节介绍。
(4)  服务
服务的定义方法在语法上等同于面向对象语言中定义接口。Thrift编译器会产生实现这些接口的client和server桩。具体参见后面的部分。

2. 枚举类型

<span style="font-size:14px;">enum NewsType {TOPNEWS,//aSPORTS = 2,//bTECNOLOGY = 3,NBA = 0xa,//cEDU = 5}//dstruct News {  1: i32 id;  2: string title;  3: string content;  4: string source;  5: string author;  6: double score;7: i64 readNum;8: NewsType newsType = NewsType.SPORTS; //e} </span>

说明:
a.  编译器默认从0开始赋值
b.  可以赋予某个常量某个整数
c.  允许常量是十六进制整数
d.  末尾没有逗号
e.  给常量赋缺省值时,使用常量的全称
注意,不同于protocol buffer,thrift不支持枚举类嵌套,枚举常量必须是32位的正整数

2.3. 注释
Thrfit支持shell注释风格,C/C++语言中单行或者多行注释风格

# This is a valid comment./* * This is a multi-line comment. * Just like in C. */ // C++/Java style single-line comments work just as well.

2.4. 命名空间
Thrift中的命名空间同C++中的namespace和java中的package类似,它们均提供了一种组织(隔离)代码的方式。因为每种语言均有自己的命名空间定义方式(如python中有module),thrift允许开发者针对特定语言定义namespace:
<span style="font-size:14px;">namespace cpp com.example.project  // anamespace java com.example.project // bnamespace py com.example.project//pythonnamespace php com.example.project  //php</span>

说明:
a.转化成namespace com { namespace example { namespace project {
b.转换成package com.example.project
2.5. 文件包含
Thrift允许thrift文件包含,用户需要使用thrift文件名作为前缀访问被包含的对象,如:

namespace java com.example.thrift.serviceinclude "NewsModel.thrift"//aservice DataSource {  string helloWorld(1: string name), bool indexNews(1: NewsModel.News indexNews), //bNewsModel.News getNewsById(1: i32 newsId), map<string,NewsModel.News> getNewsMap(1: i32 newsType), list<NewsModel.News> getNewsList(1: i32 newsType), }  

说明:
a.thrift文件名要用双引号包含,末尾没有逗号或者分号
b.注意NewsModel前缀,IDL文件名作为前缀,而不是命名空间

2.6. 定义结构体
结构体由一系列域组成,每个域有唯一整数标识符,类型,名字和可选的缺省参数组成。如:

struct News {  1: required i32 id;  //a2: required string title;  //b3: string content;  4: string source;  5: string author;  6: double score = 4.2;//d7: i64 readNum;8: NewsType newsType = NewsType.SPORTS;10: optional User user;//c} struct User {//e1: required i32 id; 2: required string userName; 3: required string password; 4: optional string nickName; } 

说明:
a.每个域有一个唯一的,正整数标识符
b.每个域可以标识为required或者optional(也可以不注明)
c.结构体可以包含其他结构体
d.域可以有缺省值
e.一个thrift中可定义多个结构体,并存在引用关系
规范的struct定义中的每个域均会使用required或者optional关键字进行标识。如果required标识的域没有赋值,thrift将给予提示。如果optional标识的域没有赋值,该域将不会被序列化传输。如果某个optional标识域有缺省值而用户没有重新赋值,则该域的值一直为缺省值。
与service不同,结构体不支持继承,即,一个结构体不能继承另一个结构体。
2.7.  定义服务
在流行的序列化/反序列化框架(如protocol buffer)中,thrift是少有的提供多语言间RPC服务的框架。
Thrift编译器会根据选择的目标语言为server产生服务接口代码,为client产生桩代码。

namespace java com.example.thrift.serviceinclude "NewsModel.thrift"//“DataSource”与“{”之间需要有空格!!!service DataSource {  string helloWorld(1: string name), //abool indexNews(1: NewsModel.News indexNews), //bNewsModel.News getNewsById(1: i32 newsId), //cmap<string,NewsModel.News> getNewsMap(1: i32 newsType), list<NewsModel.News> getNewsList(1: i32 newsType), // ”oneway”标识符表示client发出请求后不必等待回复(非阻塞)直接进行下面的操作, // ”oneway”方法的返回值必须是void oneway void zip()   // d}  

说明:
a. 函数定义可以使用逗号或者分号标识结束
b. 参数可以是基本类型或者结构体,参数是只读的(const),不可以作为返回值!!!
c. 返回值可以是基本类型或者结构体
d. 返回值可以是void
注意,函数中参数列表的定义方式与struct完全一样
Service支持继承,一个service可使用extends关键字继承另一个service

三、  编译&产生代码
WINDOWS配置thrift开发环境
1.安装thrift:到thrift官网下载exe文件,下载地址:http://thrift.apache.org/download。然后将文件重命名为thrift.exe,拷贝到F:\thrift目录下(或者任何目录下),然后就可以在dos环境下使用了,如下:
F:\thrift>thrift -gen java D:\mywork\javaProject\thriftTest\test.thrift ,输出的java文件默认输出到当前目录下F:\thrift,也可以使用-o参数指定输出路径。

在Windows环境下进行编译时出现以下问题,如图:


原来是编码问题,最后统一thrift文件的编码为UTF-8就可以正常编译通过了。

四、编写Client与Service端
1.下载相关依赖包
a. libthrift.jar
b. slf4j-api.jar
c. slf4j-simple.jar

2.编写接口实现代码

package com.example.thrift.impl;import java.util.List;import java.util.Map;import org.apache.thrift.TException;import com.example.thrift.model.News;import com.example.thrift.service.DataSource;public class DataSourceHandler implements DataSource.Iface{@Overridepublic String helloWorld(String name) throws TException {// TODO Auto-generated method stubreturn "hello "+name+",welcom to thrift!";}@Overridepublic boolean indexNews(News indexNews) throws TException {// TODO Auto-generated method stubreturn false;}@Overridepublic News getNewsById(int newsId) throws TException {News news = new News();news.setId(1000);news.setAuthor("Ricky Feng");news.setContent("thrift demo");return news;}@Overridepublic Map<String, News> getNewsMap(int newsType) throws TException {// TODO Auto-generated method stubreturn null;}@Overridepublic List<News> getNewsList(int newsType) throws TException {// TODO Auto-generated method stubreturn null;}}

3.编写server代码

package com.example.thrift;import org.apache.thrift.TProcessor;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.server.TServer;import org.apache.thrift.server.TSimpleServer;import org.apache.thrift.transport.TServerSocket;import org.apache.thrift.transport.TTransportException;import com.example.thrift.impl.DataSourceHandler;import com.example.thrift.service.DataSource;public class HelloServer {public static final int SERVER_PORT = 8090;public static void main(String[] args) {startServer();}private static void startServer() {try {System.out.println("HelloServer TSimpleServer start ....");TProcessor tprocessor = new DataSource.Processor<DataSource.Iface>(new DataSourceHandler());// 简单的单线程服务模型,一般用于测试TServerSocket serverTransport = new TServerSocket(SERVER_PORT);TServer.Args tArgs = new TServer.Args(serverTransport);tArgs.processor(tprocessor);tArgs.protocolFactory(new TBinaryProtocol.Factory());TServer server = new TSimpleServer(tArgs);server.serve();} catch (TTransportException e) {e.printStackTrace();}}}

4.编写client代码

package com.example.thrift;import org.apache.thrift.TException;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.protocol.TProtocol;import org.apache.thrift.transport.TSocket;import org.apache.thrift.transport.TTransport;import org.apache.thrift.transport.TTransportException;import com.example.thrift.service.DataSource;public class HelloClient {public static final String SERVER_IP = "localhost";public static final int SERVER_PORT = 8090;public static final int TIMEOUT = 30000;public static void main(String[] args) {startClient();}private static void startClient() {TTransport transport = null;try {System.out.println("HelloClient start ....");transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);// 协议要和服务端一致TProtocol protocol = new TBinaryProtocol(transport);// TProtocol protocol = new TCompactProtocol(transport);// TProtocol protocol = new TJSONProtocol(transport);DataSource.Client client = new DataSource.Client(protocol);transport.open();String result = client.helloWorld("Ricky");System.out.println("Thrify client result =: " + result);} catch (TTransportException e) {e.printStackTrace();} catch (TException e) {e.printStackTrace();} finally {if (null != transport) {transport.close();}}}}


先运行HelloServer启动服务,然后运行HelloClient就可以看见控制台打印:

HelloClient start ....
Thrify client result =: hello Ricky,welcom to thrift!

说明客户端调用成功啦!

关于Thrift使用的详细示例可以参考Apache Thrift网站上的Tutorial,地址:http://thrift.apache.org/tutorial/java



最后附上示例代码下载地址:http://download.csdn.net/detail/fx_sky/7499361




0 0
原创粉丝点击