Apache Thrift是一个由Facebook开发的RPC框架,目标是尽可能高效、无缝地跨语言进行可靠、高性能的通信和数据序列化。
RPC
RPC全称为Remote Procedure Call,意为远程过程调用。
假设有两个应用A和B分别部署在两台服务器上,当应用A要调用应用B的某个方法时,因为两个应用不在同一进程中,不能够直接进行调用,那就涉及到网络传输。在A和B之间搭建一条网络通道,A将参数传给B,B接收到参数后再将方法执行结果返回给A。这个过程中涉及到很多东西,比如说Socket、多线程、网络I/O等, Thrift就是一个封装了这些技术的框架,以便开发人员进行快速开发。
跨语言
Thrift通过IDL语言(Interface Description Language,接口描述语言)来实现跨语言技术。在.thrift文件中定义接口和属性数据类型,然后利用thrift提供编译器将其生成为不同开发语言的类,以满足不同种语言的开发者。如Java、C++等。生成的类中不仅包含类的属性、接口,还有RPC协议层和传输层的实现代码。
协议栈结构
Thrift是一种C/S架构体系。code层是开发者自行实现的业务逻辑的代码,第二层是由thrift编译器自动生成的代码,主要用于数据的接收、解析、发送。
Server端接收到Client的请求之后,将请求转发给Processor进行处理。Processor负责对Client的请求进行响应,主要包括RPC请求转发、调用参数解析、业务逻辑调用、返回值写回等处理。Tprotocal及其以下是thrift的传输协议及底层I/O通信。TProtocol负责解析结构化数据,将结构化数据转化为字节流给TTransport进行传输。TTransport是与底层数据传输密切相关的传输层,负责以字节流方式接收和发送消息体,不关注是什么数据类型。底层IO负责实际的数据传输,包括socket、文件和压缩数据流等。
Demo
项目结构
Async类是异步调用,暂不用关注
Hello.thrift文件
namespace java xxx
service Hello{
string helloString(1:string para);
i32 helloInt(1:i32 para);
bool helloBoolean(1:bool para);
void helloVoid();
string helloNull();
}
写好Hello.thrift文件后,在Hello.thrift所在目录下执行thrift命令生成相关类文件:thrift -r -gen java Hello.thrift
(默认已经安装thrift环境,如要生成其他语言的类,将java换为其他语言,如c++)。然后将生成的类文件移至项目目录下。
相关依赖
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.8.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
HelloServiceImpl类
package com.service;
import com.xxx.Hello;
import org.apache.thrift.TException;
public class HelloServiceImpl implements Hello.Iface {
@Override
public String helloString(String para) throws TException {
System.out.println("helloString is called......");
return "Hi," + para + "! Welcome to thrift.";
}
@Override
public int helloInt(int para) throws TException {
System.out.println("helloInt is called......");
return para;
}
@Override
public boolean helloBoolean(boolean para) throws TException {
System.out.println("helloBoolean is called......");
return para;
}
@Override
public void helloVoid() throws TException {
System.out.println("helloVoid is called......");
System.out.println("Hello World!");
}
@Override
public String helloNull() throws TException {
System.out.println("helloNull is called......");
return null;
}
}
HelloServer类
package com.server;
import com.xxx.Hello;
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;
import org.apache.thrift.transport.TTransportException;
import com.service.HelloServiceImpl;
public class HelloServer {
public static void main(String[] args) {
try {
// 设置服务端口
TServerSocket socket = new TServerSocket(8090);
// 设置通信协议为二进制格式
TBinaryProtocol.Factory factory = new TBinaryProtocol.Factory();
// 关联处理器与Hello服务的实现
TProcessor tProcessor = new Hello.Processor<Hello.Iface>(new HelloServiceImpl());
TThreadPoolServer.Args tArgs = new TThreadPoolServer.Args(socket);
tArgs.processor(tProcessor);
tArgs.protocolFactory(new TBinaryProtocol.Factory());
// 线程池服务模型, 使用标准的阻塞式IO,预先创建一组线程处理请求
TServer tServer = new TThreadPoolServer(tArgs);
System.out.println("Server starting......");
tServer.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
}
HelloClient类
package com.client;
import com.xxx.Hello;
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 HelloClient {
public static void main(String[] args) {
try {
// 设置调用的服务地址为本地,端口是8090
TTransport tTransport = new TSocket("localhost", 8090);
tTransport.open();
// 设置传输协议为二进制
TProtocol protocol = new TBinaryProtocol(tTransport);
Hello.Client client = new Hello.Client(protocol);
// 调用服务的方法
System.out.println(client.helloBoolean(false));
System.out.println(client.helloInt(3));
System.out.println(client.helloString("vi"));
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
}
}
}
Thrift系列博客:
Thrift(一)——基本使用与概念
Thrift(二)——数据类型
Thrift(三)——传输层、协议、处理器、服务端
Thrift(四)——几种服务端类型