thrift是由facebook开发用做系统内各语言之间的RPC通信 。主要特点是可以跨多语言,并且能承受高并发访问。在使用的过程中,跟同为RPC的hessian比较,最令人印象深刻的是,需要定义一个简单的定义文件中的数据类型和服务接口,以便生成RPC客户端和服务器通信的无缝跨编程语言,所以开发中,稍显麻烦,不过这也是他的优势所在。
从使用的角度来看,如果都是基于java的系统。那么用hessian会方便很多。如果设计到多种语言的系统交互,并且访问量很大 ,超过1000 req/s的话,那么用thrift不失为一个好的选择。
目前thrift 支持在linux和window使用,当然首推linux下使用。这里提供在window下的使用配置,仅作学习参考。
Thrift官网
访问thrift 官方网站 http://thrift.apache.org/download ,网站提供了基于linux和window的安装文件。我们选择 thrift-0.9.3.exe 文件。为了方便,可以把linux的版本也一起下载下来。方便以后在linux安装。
这里我下载后,存放在D:\tp\thrift 下,改名为thrift.exe
打开cmd ,进入该目录,查看thrift版本。
。
很简单,thrift已经可以使用了。接下来我们需要定义HelloThrift.thrift文件(这就是开头所讲的接口自定义文件,可以用来生成不同语言代码)。
HelloThrift.thrift
namespace java com.example.thrift
service HelloThrift{
string sayHelloByName(1:string userName)
}
namespace: 声明文件命名空间,如果用过struts2的朋友,应该很容易理解,
java 表示用java语言的方式 ,com.example.thrift 这个就是java语言的包定义。
service :这个表明是一个服务
sayHelloByName: 这个就是我们定义的一个服务接口了,返回值为string ,第一个参数为字符串类型的userName
thrift支持基本类型和结构体,具体的整理不做阐述,网上很多地方都有。
生成java 代码
打开cmd,进入到thrift目录下,使用thrfit命令,生成HelloThrift.thrift的java代码。
D:\tp\thrift>thrift -gen java HelloThrift.thrift
会看到目录下多一个gen-java的文件夹,进去可以看到会生成一个com >example>thrift的目录。下面有个HelloThrift.java的文件。
现在我用eclipse 创建一个工程,用来实现服务端和客户端的通讯。
把HelloThrift.java文件放进工程里面。
添加thrift支持
基于maven的项目 在pom.xml中添加
<!-- 添加thrift 支持 -->
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
或者到导入jar包到项目中。
编写服务器端
首先我们编写接口的具体实现。
HelloThriftImpl.java
package com.example.thrift.service;
import org.apache.thrift.TException;
import com.example.thrift.HelloThrift;
public class HelloThriftImpl implements HelloThrift.Iface {
@Override
public String sayHelloByName(String userName) throws TException {
return "hello "+userName;
}
}
ThriftSerivice
接下来。我们需要把接口实现注册到服务,并启动接口服务,以便提供给客户端调用。这里直接使用非阻塞服务器端 TThreadedSelectorServer 两个线程池 ,一个负责client接入,一个负责业务处理。除了TThreadedSelectorServer,还有其他服务器端类型。
package com.example.thrift.service;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadedSelectorServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;
import com.example.thrift.HelloThrift;
public class ThriftSerivice {
//服务端口
public static final int port=8089;
public void startServer(){
try{
//创建processor 对Client的请求做出相应,包括RPC请求转发,调用 参数解析和用户逻辑调用,返回值写回等处理步骤
TProcessor tp=new HelloThrift.Processor<HelloThrift.Iface>(new HelloThriftImpl());
//TNonblockingServerSocket 传输通道 - 非阻塞方式
TNonblockingServerSocket ts=new TNonblockingServerSocket(port);//指定端口
TThreadedSelectorServer.Args targs=new TThreadedSelectorServer.Args(ts);//注册到tserver
targs.processor(tp);
//TFramedTransport 异步IO,需要使用TFramedTransport,它将分块缓存读取。
targs.transportFactory(new TFramedTransport.Factory());
//TBinaryProtocol : 二进制格式协议
targs.protocolFactory(new TBinaryProtocol.Factory());
//启动server 负责接收Client的请求,并将请求转发到Processor进行处理。TServer主要 任务就是高效的接受Client的请求,特别是在高并发请求的情况下快速完成请求
//非阻塞服务器端 TThreadedSelectorServer 两个线程池 ,一个负责client接入,一个负责业务处理
TServer server=new TThreadedSelectorServer(targs);
System.out.println("-----------start thriftserver on "+port);
server.serve();
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public static void main(String[] args) {
ThriftSerivice ts=new ThriftSerivice();
ts.startServer();
}
}
运行ThriftSerivice 开始监听8089端口的请求
-----------start thriftserver on 8089
编写客户端
ThriftClien.java
package com.example.thrift.client;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.apache.thrift.TException;
import org.apache.thrift.async.AsyncMethodCallback;
import org.apache.thrift.async.TAsyncClientManager;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingSocket;
import org.apache.thrift.transport.TNonblockingTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import com.example.thrift.HelloThrift;
import com.example.thrift.HelloThrift.AsyncClient;
import com.example.thrift.HelloThrift.AsyncClient.sayHelloByName_call;
public class ThriftClient {
public static final String SERVERIP="localhost";
public static final int PORT=8089;
public static final int TIMEOUT=3000;
//阻塞服务,客户端调用
public void nioServerClinet (){
TTransport tp=null;
try{
/*TTransport所支持的几种主要的传输类型为:
* 1. TSocket 使用阻塞的Socket进行IO传输
* 2. TFramedTransport 使用一个带Buffer的Socket进行IO传输,使用NoblockingServer 的时候会需要使用TFramedTransport
* 3. TFileTransport 使用文件进行IO传输
* 4. TZlibTransport 与其他的TTransport配合使用,完成数据的压缩传输
*/
tp=new TFramedTransport(new TSocket(SERVERIP,PORT,TIMEOUT));
//协议TBinaryProtocol, 要跟服务器端保持一致
TProtocol tpro=new TBinaryProtocol(tp);
//注册客户端
HelloThrift.Client client=new HelloThrift.Client(tpro);
tp.open();
long l=System.currentTimeMillis();
client.sayHelloByName("jacky"+i);
System.out.println("阻塞服务,客户端调用耗时:"+(System.currentTimeMillis()-l));
tp.close();
}catch(TTransportException e){
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ThriftClient tc=new ThriftClient();
tc.nioServerClinet();
}
运行ThriftClient ,客户端输出
客户端调用耗时:21,结果:hello jacky