已转移
使用经验
client端
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 HelloClientDemo {
public static final String SERVER_IP = "localhost";
public static final int SERVER_PORT = 8090;
public static final int TIMEOUT = 30000;
public 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("Thrify client result =: " + 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) {
HelloClientDemo client = new HelloClientDemo();
client.startClient("Michael");
}
}
server
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;
public class HelloServerDemo {
public static final int SERVER_PORT = 18090;
public void startServer() {
try {
System.out.println("HelloWorld TSimpleServer start ....");
TProcessor tprocessor = new HelloWorldService.Processor<HelloWorldService.Iface>(
new HelloWorldImpl());
// HelloWorldService.Processor<HelloWorldService.Iface> tprocessor =
// new HelloWorldService.Processor<HelloWorldService.Iface>(
// new HelloWorldImpl());
// 简单的单线程服务模型,一般用于测试
TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
TServer.Args tArgs = new TServer.Args(serverTransport);
tArgs.processor(tprocessor);
tArgs.protocolFactory(new TBinaryProtocol.Factory());
// tArgs.protocolFactory(new TCompactProtocol.Factory());
// tArgs.protocolFactory(new TJSONProtocol.Factory());
TServer server = new TSimpleServer(tArgs);
server.serve();
} catch (Exception e) {
System.out.println("Server start error!!!");
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
HelloServerDemo server = new HelloServerDemo();
server.startServer();
}
}
Thrift的主要组件
Transport:传输组件,类似与Java中的IO流、socket
Protocol:提供协议和编解码的组件
Process:服务端处理请求的组件
ServiceClient:客户端组件,与Process对应
Server:服务端组件,提供了异步、同步、半异步半同步的实现
Thrift框架的远程过程调用的工作过程如下:
(2) Thrift生成的特定语言的接口文件中包括客户端部分和服务器部分;
(3)客户端通过接口文件中的客户端部分生成一个Client对象,这个客户端对象中包含所有接口函数的存根实现,然后用户代码就可以通过这个Client对象来调用thrift文件中的那些接口函数了,但是,客户端调用接口函数时实际上调用的是接口函数的本地存根实现
(4)接口函数的存根实现将调用请求发送给thrift服务器端,然后thrift服务器根据调用的函数名和函数参数,调用实际的实现函数来完成具体的操作
(5)Thrift服务器在完成处理之后,将函数的返回值发送给调用的Client对象;
(6) Thrift的Client对象将函数的返回值再交付给用户的调用函数
更详细的过程
(1). client代码像普通函数调用一样调用client stub函数,这个调用是本地调用,调用参数会和平常函数调用一样进行返回地址和调用参数压栈操作;
(2). client stub会把调用参数和其它信息(比如调用方法名、调用属性等,可以称为metadata)进行打包封装成message,然后通过系统调用发送该message,这个打包的过程是个序列化的过程;
(3). client寻求到服务端的地址,然后通过本地操作系统经由某种协议,将上述message发送给server端;
(4). server端的操作系统接收message后将其传递给server stub;
(5). server stub将message解包,得到原始传递过来的各项调用参数,解包的过程是反序列化的过程;
(6). server stub调用server端的本地函数,然后将得到的结果按照上述类似的步骤反向传递给client作为结果返回。当然整个过程也可能不那么顺利,那么也应该产生合适的状态码、异常信息作为返回。
所以RPC实际是通过client stub和server stub起到一个代理的作用,将client的请求转发到server端去操作,并将操作得到的结果回传,因为传递是跨进程、跨主机的,所以必须进行序列化和反序列化的过程来保证消息的正确性
基于java注解的thrift
注解说明
service <-> @ThriftService
struct <-> @ThriftStruct
struct 属性 <-> @ThriftField
enum <-> @ThriftEnumValue
method<->ThriftMethod
constuctor↔ThriftConstructor
field ↔ ThriftField
枚举类型可以直接传输
需要配置 thrift-publish-beans.xml服务端,常用 thrift-client-beans.xml 客户端没有webapp