我们用thrift-0.90.exe能够自动生成代码,仍用UserService.thrift为列
首先让我们先看一下自动生成的UserService类的结构
从这个类的结构中我们可以看到,主要有两个接口,两个Client,一个Processor,两个辅助的类*_agrs,*_result,*就是服务中的方法名称。
第一部分:接口部分:Iface、AsyncIface两个接口。
两个接口中的方法就是我们在thrift文件中定义的方法。例如:
在UserService.thrift中我们这样定义的:
service UserService {
list<User> getUser() throws (1:Ex.thriftDataException dataEx,2:Ex.thriftBusinessException businessEx,3:Ex.thriftSystemException systemEx)
}
则在这两个接口中创建如下:
public interface Iface {
public List<User> getUser() throws cn.stq.thrift.exception.thriftDataException, cn.stq.thrift.exception.thriftBusinessException, cn.stq.thrift.exception.thriftSystemException, org.apache.thrift.TException;
}
public interface AsyncIface {
public void getUser(org.apache.thrift.async.AsyncMethodCallback<AsyncClient.getUser_call> resultHandler) throws org.apache.thrift.TException;
}
Iface这个接口用于同步调用,AsyncIface这个接口用于异步调用,并且AsyncIface接口方法中多了一个参数。
通常我们在实现服务的地方要实现这个接口。例如:
package cn.stq.thrift;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.thrift.TException;
import cn.ruida.sms.portal.domain.User;
import cn.stq.thrift.exception.thriftBusinessException;
import cn.stq.thrift.exception.thriftDataException;
import cn.stq.thrift.exception.thriftSystemException;
public class UserServiceImpl implements UserService.Iface{
public List<Map<String, String>> getUser() throws thriftDataException,
thriftBusinessException, thriftSystemException, TException {
List<Map<String, String>> list = new ArrayList<Map<String,String>>();
Map<String,String>map = new HashMap<String, String>();
map.put("loginName", "zhangsan");
map.put("birthday", "2014-01-01");
map.put("realName", "张三");
list.add(map);
return list;
}
private List<Map<String, String>> getUser(List<User> list,
List<Map<String, String>> users) {
for(User user:list){
if(user==null){
continue;
}
Map<String,String>map = new HashMap<String, String>();
map.put("loginName", user.getLoginName());
map.put("birthday", user.getBirthday());
map.put("realName", user.getRealName());
users.add(map);
}
return users;
}
}
并且在服务端创建TProcessor的是否也用到了这个接口:
TProcessor processor = new UserService.Processor<UserService.Iface>(new UserServiceImpl());
第二个部分:两个Client类 Client和AsyncClient,这两个Client分别对应上面的两个Iface接口,这两个Client分别实现了这两个接口。
Client类中有一下几个部分:Factory类,服务方法,send_*和recv_*方法
1)Factory类中提供了获取Client的方法。
public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {
public Factory() {}
public Client getClient(org.apache.thrift.protocol.TProtocol prot) {
return new Client(prot);
}
public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {
return new Client(iprot, oprot);
}
}
第一个getClient方法只传入了一个TProtocol协议对象,第二个getClient方法传入了两个TProtocol协议对象,
iprot:表示输入协议对象,oprot:表示输出协议对象。
前者的方法只有一个协议对象,说明输入协议对象和输出协议对象是用的同一个对象。
2)服务方法。
这里所说的服务方法就是Iface接口中定义的方法,这个服务方法在每一个thrift文件生成的类中实现是相同的。
public List<User> getUser() throws cn.stq.thrift.exception.thriftDataException, cn.stq.thrift.exception.thriftBusinessException, cn.stq.thrift.exception.thriftSystemException, org.apache.thrift.TException
{
send_getUser();
return recv_getUser();
}
这个服务方法首先调用send_*()方法,然后返回一个recv_*()方法。
3)send_*和revc_*方法
这里的*表示的是Iface接口的方法名称,不同的Iface,*是不同的。例如在UserService中方法名为getUser,则send_getUser()和recv_getUser().
send_*方法
public void send_getUser() throws org.apache.thrift.TException
{
getUser_args args = new getUser_args();
sendBase("getUser", args);
}
revc_*方法
public List<User> recv_getUser() throws cn.stq.thrift.exception.thriftDataException, cn.stq.thrift.exception.thriftBusinessException, cn.stq.thrift.exception.thriftSystemException, org.apache.thrift.TException
{
getUser_result result = new getUser_result();
receiveBase(result, "getUser");
if (result.isSetSuccess()) {
return result.success;
}
if (result.dataEx != null) {
throw result.dataEx;
}
if (result.businessEx != null) {
throw result.businessEx;
}
if (result.systemEx != null) {
throw result.systemEx;
}
throw new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.MISSING_RESULT, "getUser failed: unknown result");
}
}
第三部分:Processor类
这个类的作用封装从输入输出流中读写数据的操作,它实现了TProcessor接口。这个类在整个通信的Processor层,即处理层,是协议层与用户实现的服务代码的纽带。
第四部分:两个辅助的类*_agrs,*_result
*_agrs类封装了服务方法中的参数,getUser()方法中没有参数,如果有参数的话,则参数就是*_agrs类的属性。并且在thrift文件定义的enum、struct、都在这个类中
public static class getUser_args implements org.apache.thrift.TBase<getUser_args, getUser_args._Fields>, java.io.Serializable, Cloneable {
private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("getUser_args");
*_result类封装了返回值和抛出的异常。如果有返回值的话,会存储在success属性中
public getUser_result getResult(I iface, getUser_args args) throws org.apache.thrift.TException {
getUser_result result = new getUser_result();
try {
result.success = iface.getUser();
} catch (cn.stq.thrift.exception.thriftDataException dataEx) {
result.dataEx = dataEx;
} catch (cn.stq.thrift.exception.thriftBusinessException businessEx) {
result.businessEx = businessEx;
} catch (cn.stq.thrift.exception.thriftSystemException systemEx) {
result.systemEx = systemEx;
}
return result;
}
}
通过上面的内容,我们对thrift文件自动生成的代码有了一个大致的了解。也就是我们对thrift的通信协议有了一定的了解,接下来我们就需要了解服务端和客户端是怎样的工作的了。