我们用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的通信协议有了一定的了解,接下来我们就需要了解服务端和客户端是怎样的工作的了。