Thrift小记
Thrit用的不多,也不够深入,这里小记一笔。
关于Thrift环境如何安装,可以参考官网。?
Thrit跟Java有数据类型的映射关系:
/** * The first thing to know about are types. The available types in Thrift are: * * bool Boolean, one byte * byte Signed byte * i16 Signed 16-bit integer - short * i32 Signed 32-bit integer - int * i64 Signed 64-bit integer - long * double 64-bit floating point value - double * string String * binary Blob (byte array) * map<t1,t2> Map from one type to another * list<t1> Ordered list of one type * set<t1> Set of unique elements of one type */
?我就不罗嗦了了,能看到这里的都能自动理解。
?
RPC的核心就是传参调用,参数抛不开基本数据类型、集合,更常用的是自定义对象。
在Thrift中,需要将自定义对象预先定义,类似于C语言编译要求。或者可以include其他thrift文件。
这里用Profile作为对象载体,这里Java的class对应Thrit中的struct,interface对应service。
做一个操作Profile的接口实现,代码如下:
namespace java org.zlex.support.thriftstruct Profile {1: string name,2: i32 score,3: bool enable} service ProfileService { string updateName(1:Profile profile, 2:string name) i32 updateScore(1:Profile profile, 2:i32 score) map<string,string> toMap(1:Profile profile)}
保存为Profile.thrift
?
执行命令,生成Java代码:
thrift -r -gen java Profile.thrift
生成的代码详见附件。自动生成的代码中,冗余还是不少。修改代码的冲动闪过,保持原生态。
?
针对接口做个实现类:
/** * Mar 14, 2013 */package org.zlex.support.thrift.impl;import java.util.HashMap;import java.util.Map;import org.apache.thrift.TException;import org.zlex.support.thrift.Profile;import org.zlex.support.thrift.ProfileService.Iface;/** * * @author snowolf * @version 1.0 * @since 1.0 */public class ProfileServiceImpl implements Iface {/* * (non-Javadoc) * * @see * org.zlex.support.thrift.ProfileService.Iface#updateName(org.zlex.support * .thrift.Profile, java.lang.String) */@Overridepublic String updateName(Profile profile, String name) throws TException {profile.setName(name);return profile.getName();}/* * (non-Javadoc) * * @see * org.zlex.support.thrift.ProfileService.Iface#updateScore(org.zlex.support * .thrift.Profile, int) */@Overridepublic int updateScore(Profile profile, int score) throws TException {profile.setScore(profile.getScore() + score);return profile.getScore();}/* * (non-Javadoc) * * @see * org.zlex.support.thrift.ProfileService.Iface#toMap(org.zlex.support.thrift * .Profile) */@Overridepublic Map<String, String> toMap(Profile profile) throws TException {Map<String, String> map = new HashMap<String, String>();map.put("name", profile.getName());map.put("score", "" + profile.getScore());map.put("isEnable", "" + profile.isEnable());return map;}}
?
做一个Server实现,“非阻塞&高效二进制编码”:
/** * Mar 14, 2013 */package org.zlex.support.thrift;import org.apache.log4j.Logger;import org.apache.thrift.TProcessorFactory;import org.apache.thrift.protocol.TCompactProtocol;import org.apache.thrift.server.THsHaServer;import org.apache.thrift.server.TServer;import org.apache.thrift.transport.TFramedTransport;import org.apache.thrift.transport.TNonblockingServerSocket;import org.apache.thrift.transport.TTransportException;import org.zlex.support.thrift.impl.ProfileServiceImpl;/** * * @author snowolf * @version 1.0 * @since 1.0 */public class Server {/** * Logger for this class */private static final Logger logger = Logger.getLogger(Server.class);/** * */private int port;/** * @param port */public Server(int port) {this.port = port;}/** * */@SuppressWarnings({ "rawtypes", "unchecked" })public void start() {try {TNonblockingServerSocket socket = new TNonblockingServerSocket(port);final ProfileService.Processor processor = new ProfileService.Processor(new ProfileServiceImpl());THsHaServer.Args arg = new THsHaServer.Args(socket);// 高效率的、密集的二进制编码格式进行数据传输// 使用非阻塞方式,按块的大小进行传输,类似于 Java 中的 NIOarg.protocolFactory(new TCompactProtocol.Factory());arg.transportFactory(new TFramedTransport.Factory());arg.processorFactory(new TProcessorFactory(processor));TServer server = new THsHaServer(arg);logger.info("服务启动-使用:非阻塞&高效二进制编码");server.serve();} catch (TTransportException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}}
?
服务器测试用例:
/** * Mar 14, 2013 */package org.zlex.support.thrift;import org.junit.Before;import org.junit.Test;/** * * @author snowolf * @version 1.0 * @since 1.0 */public class ServerTest {public final static int PORT = 9999;private Server server;@Beforepublic void init() {server = new Server(PORT);}@Testpublic void test() {server.start();}}
?
客户端测试用例:
/** * Mar 14, 2013 */package org.zlex.support.thrift;import static org.junit.Assert.*;import java.util.Map;import org.apache.thrift.TApplicationException;import org.apache.thrift.TException;import org.apache.thrift.protocol.TCompactProtocol;import org.apache.thrift.protocol.TProtocol;import org.apache.thrift.transport.TFramedTransport;import org.apache.thrift.transport.TSocket;import org.apache.thrift.transport.TTransport;import org.apache.thrift.transport.TTransportException;import org.junit.Test;/** * * @author snowolf * @version 1.0 * @since 1.0 */public class ClientTest {public final static int PORT = 9999;public static final String address = "localhost";public static final int clientTimeout = 30000;@Testpublic void test() {TTransport transport = new TFramedTransport(new TSocket(address, PORT,clientTimeout));TProtocol protocol = new TCompactProtocol(transport);ProfileService.Client client = new ProfileService.Client(protocol);try {transport.open();Profile profile = new Profile();profile.setName("Snowolf");Map<String, String> map = client.toMap(profile);assertEquals(map.get("name"),"Snowolf");} catch (TApplicationException e) {System.out.println(e.getMessage() + " " + e.getType());} catch (TTransportException e) {e.printStackTrace();} catch (TException e) {e.printStackTrace();}transport.close();}}
?
Client调用Server接口,将Profile对象交由Server处理,转换为Map。
?
如果需要Thirif承载高并发的负载,可以通过nginx来完成负载均衡的实现,详见
?
小记完毕,Go Home!
?
?
?