Thrift小记

原文链接:https://my.oschina.net/mohaiyong/blog/221302

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
 */

 我就不罗嗦了了,能看到这里的都能自动理解。Thrift小记

 

RPC的核心就是传参调用,参数抛不开基本数据类型、集合,更常用的是自定义对象。

在Thrift中,需要将自定义对象预先定义,类似于C语言编译要求。或者可以include其他thrift文件。

这里用Profile作为对象载体,这里Java的class对应Thrit中的struct,interface对应service。

做一个操作Profile的接口实现,代码如下:

namespace java org.zlex.support.thrift

struct 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)
	 */
	@Override
	public 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)
	 */
	@Override
	public 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)
	 */
	@Override
	public 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 中的 NIO
			arg.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;

	@Before
	public void init() {
		server = new Server(PORT);
	}

	@Test
	public 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;

	@Test
	public 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来完成负载均衡的实现,详见

Nginx扩展(一):nginx_tcp_proxy_module

 

小记完毕,Go Home!

 

 

 

转载于:https://my.oschina.net/mohaiyong/blog/221302

上一篇:Thrift使用入门---RPC服务


下一篇:Thrift 0.9.3 Mac安装 实测有效