Thrift是一个跨语言的服务部署框架,最初由Facebook于2007年开发,2008年进入Apache开源项目。Thrift通过一个中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。
1.安装thrift.exe
2.配置maven,通过maven执行IDL生成代码工作
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>thriftTest</groupId>
<artifactId>simplecConsole</artifactId>
<version>1.0-SNAPSHOT</version>
<name>thrift-demo-console</name>
<description>A maven project to study thrift.</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<compiler-plugin.version>2.3.2</compiler-plugin.version>
<thrift.version>0.9.3</thrift.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>${thrift.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<!-- <plugin> <groupId>org.apache.thrift.tools</groupId> <artifactId>maven-thrift-plugin</artifactId> <version>0.1.11</version> <configuration> <thriftExecutable>D:\Thrift\thrift.exe</thriftExecutable> <generator>java</generator> <outputDirectory>src/main/java/thrift/demo</outputDirectory> <thriftSourceRoot>${project.basedir}/src/main/resources</thriftSourceRoot> </configuration> <executions> <execution> <id>thrift-sources</id> <phase>generate-sources</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>thrift-test-sources</id> <phase>generate-test-sources</phase> <goals> <goal>testCompile</goal> </goals> </execution> </executions> </plugin>-->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>compile-thrift</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<mkdir dir="src/main/java/com/anjuke/demo/thrift/auto"/>
<path id="thrift.path">
<fileset dir="${project.basedir}/src/main/resources">
<include name="**/*.thrift"/>
</fileset>
</path>
<pathconvert pathsep=" " property="thrift.files" refid="thrift.path"/>
<exec executable="D:\Thrift\thrift">
<arg value="-r --gen"/>
<arg value="java"/>
<arg value="-out"/>
<arg value="src/main/java"/>
<arg line="${thrift.files}"/>
</exec>
</tasks>
<sourceRoot>src/main/java/thrift/demo/thrift</sourceRoot>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<configuration>
<verbose>true</verbose>
<filesets>
<fileset>
<directory>${project.basedir}/src/main/java/com/anjuke/demo/thrift/auto</directory>
</fileset>
</filesets>
</configuration>
</plugin>
</plugins>
</build>
</project>
ReferenceLink
代码生成服务的所有数据协议转换,并提供接口调用系统的传输方式(TSocket,THttpTransport,TFileTransport),以及同步\异步客户端,Processor负责Client请求的响应
有阻塞,非阻塞,线程池,半同步半异步,Selector多种服务端实现模式。
TSimpleServer – 简单的单线程服务模型,常用于测试
TThreadedServer – 多线程服务模型,使用阻塞式IO,每个请求创建一个线程。(java 不支持)
TThreadPoolServer – 多线程服务模型,使用标准的阻塞式IO,预先创建一组线程处理请求。
TThreadedSelectorServer 允许你用多个线程来处理网络I/O。它维护了两个线程池,一个用来处理网络I/O,另一个用来进行请求的处理
TNonblockingServer – 多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式),只有一个线程来处理消息
THsHaServer - 半同步半异步的服务模型,一个单独的线程用来处理网络I/O,一个worker线程池用来进行消息的处理
TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
new HelloWorldImpl());
TServerSocket 阻塞型socket, 用于服务器端, accecpt到的socket类型都是TSocket(即阻塞型socket);
TNonblockingServerSocket 非阻塞型socket, 用于服务器端(NIO)
TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
new HelloWorldImpl());
TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(
SERVER_PORT);
TNonblockingServer.Args tnbArgs = new TNonblockingServer.Args(
tnbSocketTransport);
tnbArgs.processor(tprocessor);
tnbArgs.transportFactory(new TFramedTransport.Factory());
tnbArgs.protocolFactory(new TCompactProtocol.Factory());
// 使用非阻塞式IO,服务端和客户端需要指定TFramedTransport数据传输的方式
TServer server = new TNonblockingServer(tnbArgs);
server.serve();
包括同步,异步两种客户端形式
TSocket:采用TCP Socket进行数据传输,阻塞型socket,用于客户端,采用系统函数read和write进行读写数据;(BIO)
TNonblockingSocket (NIO) 异步客户端使用
TSocket:采用TCP Socket进行数据传输,阻塞型socket,用于客户端,采用系统函数read和write进行读写数据;(BIO)
TNonblockingSocket (NIO) 异步客户端使用
TSSLSocket 继承TSocket,阻塞型socket, 用于客户端;采用openssl的接口进行读写数据。
THttpTransport:采用Http传输协议进行数据传输
TFileTransport – 以文件形式进行传输。
TMemoryTransport – 将内存用于I/O. java实现时内部实际使用了简单的ByteArrayOutputStream。
TZlibTransport – 使用zlib进行压缩, 与其他传输方式联合使用。当前无java实现。
TFramedTransport – 以frame为单位进行传输,非阻塞式服务中使用。类似于Java中的NIO。
TFastFramedTransport 与TFramedTransport相比,始终使用相同的Buffer,提高了内存的使用率。
TSaslClientTransport与TSaslServerTransport, 提供SSL校验
TBinaryProtocol – 二进制格式.
TCompactProtocol – 压缩格式
TDenseProtocol -继承TCompactProtocol,不包含meta信息
TJSONProtocol – JSON格式
TSimpleJSONProtocol –提供JSON只写协议, 生成的文件很容易通过脚本语言解析。
transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
// 协议要和服务端一致
TProtocol protocol = new TBinaryProtocol(transport);
HelloWorldService.Client client = new HelloWorldService.Client(protocol);
transport.open();
String result = client.sayHello(userName);
TAsyncClientManager clientManager = new TAsyncClientManager();
TNonblockingTransport transport = new TNonblockingSocket(SERVER_IP,SERVER_PORT, TIMEOUT);
TProtocolFactory tprotocol = new TCompactProtocol.Factory();
HelloWorldService.AsyncClient asyncClient = new HelloWorldService.AsyncClient(tprotocol, clientManager, transport);
System.out.println("Client start .....");
CountDownLatch latch = new CountDownLatch(1);
AsynCallback callBack = new AsynCallback(latch);
System.out.println("call method sayHello start ...");
asyncClient.sayHello(userName, callBack);
System.out.println("call method sayHello .... end");
boolean wait = latch.await(30, TimeUnit.SECONDS);
框架和时序图
struct是定义为一种对象,和面向对象语言的class差不多.,但是struct有以下一些约束:
struct Report
{
1: required string msg, //改字段必须填写
2: optional i32 type = 0; //默认值
3: i32 time //默认字段类型为optional
}
如protobuf 通过 repeated 标识实现 Containers 不同
struct Test {
1: map<Numberz, UserId> user_map,
2: set<Numberz> num_sets,
3: list<Stusers> users
}
不同于protocal buffer,thrift不支持枚举类嵌套,枚举常量必须是32位的正整数
enum EnOpType {
CMD_OK = 0, // (0)
CMD_NOT_EXIT = 2000, // (2000)
CMD_EXIT = 2001, // (2001)
CMD_ADD = 2002 // (2002)
}
struct StUser {
1: required i32 userId;
2: required string userName;
3: optional EnOpType cmd_code = EnOpType.CMD_OK; // (0)
4: optional string language = “english”
}
Thrift结构体将会被转换成面向对象语言的类。异常在语法和功能上类似于结构体,差别是异常使用关键字exception,而且异常是继承每种语言的基础异常类。
exception Extest {
1: i32 errorCode,
2: string message,
3: StUser userinfo
}
服务的定义方法在语义(semantically)上等同于面向对象语言中的接口。Thrift编译器会产生执行这些接口的client和server stub。具体参见下一节。在流行的序列化/反序列化框架(如protocal buffer)中,Thrift是少有的提供多语言间RPC服务的框架。这是Thrift的一大特色。
service SeTest {
void ping(),
bool postTweet(1: StUser user);
StUser searchTweets(1:string name);
oneway void zip()
}
Thrift中的命名空间类似于C++中的namespace和java中的package,它们提供了一种组织(隔离)代码的简便方式。名字空间也可以用于解决类型定义中的名字冲突。
namespace cpp com.example.test
namespace java com.example.test
namespace php com.example.test
便于管理、重用和提高模块性/组织性,常常分割Thrift定义在不同的文件中。包含文件搜索方式与c++一样。Thrift允许文件包含其它thrift文件,用户需要使用thrift文件名作为前缀访问被包含的对象
include "test.thrift"
...
struct StSearchResult {
1: in32 uid;
...
}
基于Thrift Type 书写IDL,文件后缀名thrift
struct User{
1:i64 id,
2:string name,
3:i64 timestamp,
4:bool vip
}
service UserService{
User getById(1:i64 id)
}
demo-github-link