IBM-Apache Thrift - 可伸缩的跨语言服务开发框架
POM:
<dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.9.2</version> </dependency>
Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。
thrift允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。
支持多种语言之间的RPC方式的通信:
php语言client可以构造一个对象,调用相应的服务方法来调用java语言的服务 ,跨越语言的C/S RPC调用 。
thrift可以用来快速的开发基于Socket的接口工具。简单的说,就是可以让人快速的写Socket Server和Client。其实不用thrift开发socket也不难,
那么为什么要用thrift开发呢?主要有两个原因,一个是因为thrift本身帮你封装了很多基本的东西,你不需要自己去写socket里面的bind,accept之类的,以及他们的逻辑。可以很快速的开发基于进程的,线程的,SSL的socket。第二个理由是标准化,跨语言和跨平台,windows不算在其中。主要是在各种Posix兼容的操作系统中都可以不需要改造基本直接可用,支持的语言种类也很多,基本你会写的,他都支持。你不会写的,他也支持。
Thrift与其他传输方式的比较
xml与JSON相比体积太大,但是xml传统,也不算复杂。
json 体积较小,新颖,但不够完善。
thrift 体积超小,使用起来比较麻烦,不如前两者轻便,但是对于1.高并发、2.数据传输量大、3.多语言环境, 满足其中2点使用 thrift还是值得的。
建立一个java rmi的流程 :
1、定义一个服务调用接口 。
2、server端:接口实现---impl的实例---注册该服务实现(端口)---启动服务。
3、client端:通过ip、端口、服务名,得到服务,通过接口来调用 。
4、rmi数据传输方式:java对象序列化 。
Thrift:
thrift --gen <language> <Thrift filename>
To recursivly generate source code from a Thrift file and all other Thrift files included by it, run
thrift -r --gen <language> <Thrift filename>
thrift-0.7.0.exe -r -gen java TestThrift.thrift 生成java 代码
thrift-0.7.0.exe -r -gen php TestThrift.thrift 生成php代码
thrift-0.7.0.exe -r -gen py TestThrift.thrift 生成python代码
thrift-0.7.0.exe -r -gen as3 TestThrift.thrift 生成as3代码
thrift-0.7.0.exe -r -gen cpp TestThrift.thrift 生成C++代码
基本概念
1.数据类型
基本类型:
bool:布尔值,true 或 false,对应 Java 的 boolean
byte:8 位有符号整数,对应 Java 的 byte
i16:16 位有符号整数,对应 Java 的 short
i32:32 位有符号整数,对应 Java 的 int
i64:64 位有符号整数,对应 Java 的 long
double:64 位浮点数,对应 Java 的 double
string:utf-8编码的字符串,对应 Java 的 String
结构体类型:
struct:定义公共的对象,类似于 C 语言中的结构体定义,在 Java 中是一个 JavaBean
容器类型:
list:对应 Java 的 ArrayList
set:对应 Java 的 HashSet
map:对应 Java 的 HashMap
异常类型:
exception:对应 Java 的 Exception
服务类型:
service:对应服务的类
2.服务端编码基本步骤:
实现服务处理接口impl
创建TProcessor
创建TServerTransport(TServerSocket)
创建TProtocol
创建TServer
启动Server
3.客户端编码基本步骤:
创建Transport
创建TProtocol
基于TTransport和TProtocol创建 Client
调用Client的相应方法
4.数据传输协议
TBinaryProtocol : 二进制格式.
TCompactProtocol : 压缩格式
TJSONProtocol : JSON格式
TSimpleJSONProtocol : 提供JSON只写协议, 生成的文件很容易通过脚本语言解析
tips:客户端和服务端的协议要一致
服务端类型:
TSimpleServer
简单的单线程服务模型,一般用于测试。
TThreadPoolServer
线程池服务模型,使用标准的阻塞式IO,预先创建一组线程处理请求。
TNonblockingServer:
使用非阻塞式IO,服务端和客户端需要指定 TFramedTransport 数据传输的方式。
例子:
1、thrift生成代码
使用thrift需要先定义接口文件demo.thrift,在thrift里简称叫IDL,全称叫Interface Description Language,接口描述语言。接口描述语言里面需要定义接口中所使用的数据类型,方法等等。
使用 Thrift 工具编译 demo.thrift,就会生成相应的 HelloWorldService.java 文件。该文件包含了在 demo.thrift 文件中描述的服务 HelloWorldService 的接口定义,即 HelloWorldService.Iface 接口,以及服务调用的底层通信细节,包括客户端的调用逻辑 HelloWorldService.Client 以及服务器端的处理逻辑 HelloWorldService.Processor,用于构建客户端和服务器端的功能。
创建一个简单的服务 HelloWordService。首先根据 Thrift 的语法规范编写脚本文件 demo.thrift:
namespace java com.service.demo service HelloWorldService{ string sayHello(1:string username) i32 helloInt(1:i32 para) bool helloBoolean(1:bool para) void helloVoid() string helloNull() }
thrift-0.9.2.exe 是官网提供的windows下编译工具,运用这个工具生成相关代码:
thrift-0.9.2.exe -r -gen java demo.thrift
生成文件目录:\gen-java\com\service\demo\HelloWorldService.java
将架包导入工程中,并将生成的HelloWordService.java拷入
2、 实现接口Iface
import org.apache.thrift.TException; public class HelloWorldServiceImpl implements HelloWorldService.Iface{ @Override public String sayHello(String username) throws TException { return "Hi," + username + " this is my first thrift demo."; } @Override public boolean helloBoolean(boolean para) throws TException { // TODO Auto-generated method stub return false; } @Override public int helloInt(int para) throws TException { // TODO Auto-generated method stub return 0; } @Override public String helloNull() throws TException { // TODO Auto-generated method stub return null; } @Override public void helloVoid() throws TException { // TODO Auto-generated method stub } }
3、创建服务端实现代码:
package com.common.test; import org.apache.thrift.TProcessor; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.server.TServer; import org.apache.thrift.server.TThreadPoolServer; import org.apache.thrift.transport.TServerSocket; public class HelloServiceServer { public static final int SERVER_PORT = 8090; public static void startServer() { try { System.out.println("HelloWorld TThreadPoolServer start ...."); TProcessor processor = new HelloWorldService.Processor(new HelloWorldServiceImpl()); TServerSocket serverTransport = new TServerSocket(SERVER_PORT); //TServerTransport serverTransport = new TServerSocket( new InetSocketAddress("0.0.0.0",9813)); TThreadPoolServer.Args ttpsArgs = new TThreadPoolServer.Args(serverTransport); ttpsArgs.processor(processor); ttpsArgs.protocolFactory(new TBinaryProtocol.Factory()); // 线程池服务模型,使用标准的阻塞式IO,预先创建一组线程处理请求。 TServer server = new TThreadPoolServer(ttpsArgs); server.serve(); /* 或者: Args trArgs=new Args(serverTransport); trArgs.processor(processor); //使用二进制来编码应用层的数据 trArgs.protocolFactory(new TBinaryProtocol.Factory(true, true)); //使用普通的socket来传输数据 //trArgs.transportFactory(new TTransportFactory()); TServer server = new TThreadPoolServer(trArgs); */ System.out.println("Start server on port "+SERVER_PORT+"..."); } catch (Exception e) { System.out.println("Server start error!!!"); e.printStackTrace(); } } /** * @param args */ public static void main(String[] args) { startServer(); } }
HelloWorld TThreadPoolServer start ....
4、创建客户端实现代码:
package com.common.test; 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; public class HelloServiceClient { public static final String SERVER_IP = "192.168.3.76"; public static final int SERVER_PORT = 8090; public static final int TIMEOUT = 30000; /** * * @param userName */ public static void startClient(String userName) { TTransport transport = null; try { transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT); // 协议要和服务端一致 TProtocol protocol = new TBinaryProtocol(transport); // TProtocol protocol = new TCompactProtocol(transport); // TProtocol protocol = new TJSONProtocol(transport); HelloWorldService.Client client = new HelloWorldService.Client(protocol); transport.open(); String result = client.sayHello(userName); System.out.println(result); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); } finally { if (null != transport) { transport.close(); } } } /** * @param args */ public static void main(String[] args) { startClient("Michael"); } }
Hi,Michael this is my first thrift demo.