thrift早期由facebook内部团队开发,主要用于实现跨语言间的方法调用,属于远程方法调用的一中,后开源纳入apache中,成为了apache thrift项目。thrift允许定义一个简单的定义文件中的数据类型和服务接口,以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。
thrift和http restful style在理解上很相似,即在接口定义层面,能达到顾名思义的效果。如下,为thrift服务定义配置文件:
demo.thrift文件
namespace java com.micmiu.thrift.demo
struct Work {
1: i32 num1 = 0,
2: i32 num2,
}
service HelloWorldService {
string sayHello(1:string username),
i32 add(1:i32 num1, 2:i32 num2),
string fuck(1:Work work)
}
以上定义了一个接口,以及接口内的三个方法sayHello, add,fuck。接下来我们要做的事情是,创建一个实现该接口方法的服务实现类(在下文中我们称呼做实现类) 以及 调用该接口方法的调用类(在下文中我们称呼做调用类)。
鉴于要提现thrift的跨语言方法调用特性,这里我们选择使用python作为thrift的调用方,java作为thrift的实现方。步骤如下:
步骤1:
生成python 和 java的thrift接口定义代码文件。这里需要用到thrfit编译器(用于动态生成接口定义代码文件,下载地址:https://thrift.apache.org/download),进入到接口定义代码文件(demo.thrift)目录,执行以下命令:
thrift.exe -r --gen java demo.thrift #生成java源码,在当前目录生成gen-java目录,对应生成的服务定义接口类为:HelloWorldService.java
thrift.exe -r --gen py demo.thrift #生成python源码,在当前目录生成gen-py目录,对应申城的服务定义接口类为:HelloWorldService.py
步骤2:
编写服务的实现类,这里我们选择用java编辑服务实现类。如下:
HelloWorldImpl.java
package com.micmiu.thrift.demo;
import org.apache.thrift.TException;
public class HelloWorldImpl implements HelloWorldService.Iface {
public HelloWorldImpl() {
// TODO Auto-generated constructor stub
}
public String sayHello(String username) throws TException {
// TODO Auto-generated method stub
return "fuck you, sir [ " + username + "]";
}
public int add(int num1, int num2) throws TException {
// TODO Auto-generated method stub
return num1 + num2;
}
public String fuck(Work work) throws TException {
// TODO Auto-generated method stub
return "fuck num :" + work.num2;
}
}
从源码不难看出,该服务类实现了demo.thrift里定义的三方法,add , sayHello, fuck。编写完成后,我们来写个sever demo让服务端先在8090端口跑起来:
HelloServerDemo.java
package com.micmiu.thrift.demo;import org.apache.thrift.TProcessor;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.protocol.TCompactProtocol;import org.apache.thrift.protocol.TJSONProtocol;import org.apache.thrift.protocol.TSimpleJSONProtocol;import org.apache.thrift.server.TServer;import org.apache.thrift.server.TSimpleServer;import org.apache.thrift.transport.TServerSocket;/** * blog http://www.micmiu.com * * @author Michael * */public class HelloServerDemo {public static final int SERVER_PORT = 8090;public void startServer() {try {System.out.println("HelloWorld TSimpleServer start ....");TProcessor tprocessor = new HelloWorldService.Processor(
new HelloWorldImpl());
// HelloWorldService.Processor tprocessor =
// new HelloWorldService.Processor(
// 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();
}
}
通过命令行编译运行或者eclipse直接编译运行HelloServerDemo,让其处于运行状态,监听8090端口请求。
步骤3:
编写调用类,这里选择python做为调用类。如下:
pclient.py
#!/usr/bin/env python
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
import sys
import glob
sys.path.append('gen-py')
# sys.path.insert(0, glob.glob('../../lib/py/build/lib*')[0])
from demo import HelloWorldService
from demo.ttypes import Work
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
def main():
# Make socket
transport = TSocket.TSocket('localhost', 8090)
# Buffering is critical. Raw sockets are very slow
transport = TTransport.TBufferedTransport(transport)
# Wrap in a protocol
protocol = TBinaryProtocol.TBinaryProtocol(transport)
# Create a client to use the protocol encoder
client = HelloWorldService.Client(protocol)
# Connect!
transport.open()
result = client.sayHello("xiaolizi")
print (result)
sum_ = client.add(1, 1)
print('1+1=%d' % sum_)
work = Work()
work.num1 = 1
work.num2 = 5
result1 = client.fuck(work)
print (result1)
# Close!
transport.close()
if __name__ == '__main__':
try:
main()
except Thrift.TException as tx:
print('%s' % tx.message)
运行,输出如下:
fuck you, sir [ xiaolizi]
1+1=2
fuck num :5
结束:
以上demo实现了python通过thrift协议调用远程java端服务,实现了我们上文提到的远程调用。当然,thrift的强大功能远远不仅于此,想要了解学习的话,可以去apache thrift官网上看看官方文档介绍,并动手实践一番。感谢各位阅读,小弟不胜笔力,文中若有错误、不当之处,欢迎指出,还请多多体谅, LOL~