读书人

【转】Apache Thrift - 可舒卷的跨语言

发布时间: 2013-04-20 19:43:01 作者: rapoo

【转】Apache Thrift - 可伸缩的跨语言服务开发框架(代码已修正)

个人学习参考所用,勿喷!

?

原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/index.html

?

对原文的修改:

1.原文的服务器端代码的BUG,不论是0.8.0还是0.6.1版本的thrift,例如以下的创建server的方式都不对(正确结果看修正后的文中代码):

Java代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. TServer?server?=?new?TThreadPoolServer(processor,?serverTransport,?proFactory);???
Java代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. TServer?server?=?new?TThreadPoolServer(processor,?serverTransport,?proFactory);???

2.增加了maven的构建方式。

3.修正启动server时候的"Failedto load class org.slf4j.impl.StaticLoggerBinder"的BUG,参考地址:http://www.slf4j.org/codes.html#StaticLoggerBinder

4.附件为maven构建的工程代码

?

前言:

? ? ? ??目前流行的服务调用方式有很多种,例如基于 SOAP 消息格式的 Web Service,基于 JSON 消息格式的 RESTful 服务等。其中所用到的数据传输方式包括 XML,JSON 等,然而 XML 相对体积太大,传输效率低,JSON 体积较小,新颖,但还不够完善。本文将介绍由 Facebook 开发的远程服务调用框架 Apache Thrift,它采用接口描述语言定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以在多种语言中,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等创建高效的、无缝的服务,其传输数据采用二进制格式,相对 XML 和 JSON 体积更小,对于高并发、大数据量和多语言的环境更有优势。本文将详细介绍 Thrift 的使用,并且提供丰富的实例代码加以解释说明,帮助使用者快速构建服务。

?

一个简单的 Thrift 实例

? ? ? ? 本文首先介绍一个简单的 Thrift 实现实例,使读者能够快速直观地了解什么是 Thrift 以及如何使用 Thrift 构建服务。

创建一个简单的服务 Hello。首先根据 Thrift 的语法规范编写脚本文件 Hello.thrift,代码如下:


清单 1. Hello.thrift

Thrift代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. namespace?java?service.demo???
  2. service?Hello{???
  3. ?string?helloString(1:string?para)???
  4. ?i32?helloInt(1:i32?para)???
  5. ?bool?helloBoolean(1:bool?para)???
  6. ?void?helloVoid()???
  7. ?string?helloNull()???
  8. }??
Thrift代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. namespace?java?service.demo???
  2. service?Hello{???
  3. ?string?helloString(1:string?para)???
  4. ?i32?helloInt(1:i32?para)???
  5. ?bool?helloBoolean(1:bool?para)???
  6. ?void?helloVoid()???
  7. ?string?helloNull()???
  8. }??

其中定义了服务 Hello 的五个方法,每个方法包含一个方法名,参数列表和返回类型。每个参数包括参数序号,参数类型以及参数名。 Thrift 是对 IDL(Interface Definition Language) 描述性语言的一种具体实现。因此,以上的服务描述文件使用 IDL 语法编写。使用 Thrift 工具编译 Hello.thrift,就会生成相应的 Hello.java 文件。该文件包含了在 Hello.thrift 文件中描述的服务 Hello 的接口定义,即 Hello.Iface 接口,以及服务调用的底层通信细节,包括客户端的调用逻辑 Hello.Client 以及服务器端的处理逻辑 Hello.Processor,用于构建客户端和服务器端的功能。

创建 HelloServiceImpl.java 文件并实现 Hello.java 文件中的 Hello.Iface 接口,代码如下:


清单 2. HelloServiceImpl.java

Java代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. package?service.demo;??
  2. ??
  3. import?org.apache.thrift.TException;??
  4. ??
  5. public?class?HelloServiceImpl?implements?Hello.Iface?{??
  6. ????@Override??
  7. ????public?boolean?helloBoolean(boolean?para)?throws?TException?{??
  8. ????????return?para;??
  9. ????}??
  10. ??
  11. ????@Override??
  12. ????public?int?helloInt(int?para)?throws?TException?{??
  13. ????????try?{??
  14. ????????????Thread.sleep(20000);??
  15. ????????}?catch?(InterruptedException?e)?{??
  16. ????????????e.printStackTrace();??
  17. ????????}??
  18. ????????return?para;??
  19. ????}??
  20. ??
  21. ????@Override??
  22. ????public?String?helloNull()?throws?TException?{??
  23. ????????return?null;??
  24. ????}??
  25. ??
  26. ????@Override??
  27. ????public?String?helloString(String?para)?throws?TException?{??
  28. ????????return?para;??
  29. ????}??
  30. ??
  31. ????@Override??
  32. ????public?void?helloVoid()?throws?TException?{??
  33. ????????System.out.println("Hello?World");??
  34. ????}??
  35. }??
Java代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. package?service.demo;??
  2. ??
  3. import?org.apache.thrift.TException;??
  4. ??
  5. public?class?HelloServiceImpl?implements?Hello.Iface?{??
  6. ????@Override??
  7. ????public?boolean?helloBoolean(boolean?para)?throws?TException?{??
  8. ????????return?para;??
  9. ????}??
  10. ??
  11. ????@Override??
  12. ????public?int?helloInt(int?para)?throws?TException?{??
  13. ????????try?{??
  14. ????????????Thread.sleep(20000);??
  15. ????????}?catch?(InterruptedException?e)?{??
  16. ????????????e.printStackTrace();??
  17. ????????}??
  18. ????????return?para;??
  19. ????}??
  20. ??
  21. ????@Override??
  22. ????public?String?helloNull()?throws?TException?{??
  23. ????????return?null;??
  24. ????}??
  25. ??
  26. ????@Override??
  27. ????public?String?helloString(String?para)?throws?TException?{??
  28. ????????return?para;??
  29. ????}??
  30. ??
  31. ????@Override??
  32. ????public?void?helloVoid()?throws?TException?{??
  33. ????????System.out.println("Hello?World");??
  34. ????}??
  35. }??

创建服务器端实现代码,将 HelloServiceImpl 作为具体的处理器传递给 Thrift 服务器,代码如下:


清单 3. HelloServiceServer.java

Java代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. package?service.server;??
  2. ??
  3. import?org.apache.thrift.TProcessor;??
  4. import?org.apache.thrift.protocol.TBinaryProtocol;??
  5. import?org.apache.thrift.protocol.TBinaryProtocol.Factory;??
  6. import?org.apache.thrift.server.TServer;??
  7. import?org.apache.thrift.server.TThreadPoolServer;??
  8. import?org.apache.thrift.transport.TServerSocket;??
  9. import?org.apache.thrift.transport.TTransportException;??
  10. import?service.demo.Hello;??
  11. import?service.demo.HelloServiceImpl;??
  12. ??
  13. public?class?HelloServiceServer?{??
  14. ????/**?
  15. ?????*?启动?Thrift?服务器?
  16. ?????*??
  17. ?????*?@param?args?
  18. ?????*/??
  19. ????@SuppressWarnings({?"rawtypes",?"unchecked",?"unused"?})??
  20. ????public?static?void?main(String[]?args)?{??
  21. ????????try?{??
  22. ????????????//?设置服务端口为?7911??
  23. ????????????TServerSocket?serverTransport?=?new?TServerSocket(7911);??
  24. ????????????//?设置协议工厂为?TBinaryProtocol.Factory??
  25. ????????????Factory?proFactory?=?new?TBinaryProtocol.Factory();??
  26. ????????????//?关联处理器与?Hello?服务的实现??
  27. ????????????TProcessor?processor?=?new?Hello.Processor(new?HelloServiceImpl());??
  28. ????????????TThreadPoolServer.Args?argss?=?new?TThreadPoolServer.Args(??
  29. ????????????????????serverTransport);??
  30. ????????????//?默认情况就是TBinaryProtocol.Factory??
  31. ????????????//?argss.inputProtocolFactory(proFactory);??
  32. ????????????//?argss.outputProtocolFactory(proFactory);??
  33. ????????????argss?=?argss.processor(processor);??
  34. ????????????TServer?server?=?new?TThreadPoolServer(argss);??
  35. ????????????System.out.println("Start?server?on?port?7911...");??
  36. ????????????server.serve();??
  37. ??
  38. ????????}?catch?(TTransportException?e)?{??
  39. ????????????e.printStackTrace();??
  40. ????????}??
  41. ????}??
  42. }??
Java代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. package?service.server;??
  2. ??
  3. import?org.apache.thrift.TProcessor;??
  4. import?org.apache.thrift.protocol.TBinaryProtocol;??
  5. import?org.apache.thrift.protocol.TBinaryProtocol.Factory;??
  6. import?org.apache.thrift.server.TServer;??
  7. import?org.apache.thrift.server.TThreadPoolServer;??
  8. import?org.apache.thrift.transport.TServerSocket;??
  9. import?org.apache.thrift.transport.TTransportException;??
  10. import?service.demo.Hello;??
  11. import?service.demo.HelloServiceImpl;??
  12. ??
  13. public?class?HelloServiceServer?{??
  14. ????/**?
  15. ?????*?启动?Thrift?服务器?
  16. ?????*??
  17. ?????*?@param?args?
  18. ?????*/??
  19. ????@SuppressWarnings({?"rawtypes",?"unchecked",?"unused"?})??
  20. ????public?static?void?main(String[]?args)?{??
  21. ????????try?{??
  22. ????????????//?设置服务端口为?7911??
  23. ????????????TServerSocket?serverTransport?=?new?TServerSocket(7911);??
  24. ????????????//?设置协议工厂为?TBinaryProtocol.Factory??
  25. ????????????Factory?proFactory?=?new?TBinaryProtocol.Factory();??
  26. ????????????//?关联处理器与?Hello?服务的实现??
  27. ????????????TProcessor?processor?=?new?Hello.Processor(new?HelloServiceImpl());??
  28. ????????????TThreadPoolServer.Args?argss?=?new?TThreadPoolServer.Args(??
  29. ????????????????????serverTransport);??
  30. ????????????//?默认情况就是TBinaryProtocol.Factory??
  31. ????????????//?argss.inputProtocolFactory(proFactory);??
  32. ????????????//?argss.outputProtocolFactory(proFactory);??
  33. ????????????argss?=?argss.processor(processor);??
  34. ????????????TServer?server?=?new?TThreadPoolServer(argss);??
  35. ????????????System.out.println("Start?server?on?port?7911...");??
  36. ????????????server.serve();??
  37. ??
  38. ????????}?catch?(TTransportException?e)?{??
  39. ????????????e.printStackTrace();??
  40. ????????}??
  41. ????}??
  42. }??

创建客户端实现代码,调用 Hello.client 访问服务端的逻辑实现,代码如下:


清单 4. HelloServiceClient.java

Java代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. package?service.client;???
  2. ?import?org.apache.thrift.TException;???
  3. ?import?org.apache.thrift.protocol.TBinaryProtocol;???
  4. ?import?org.apache.thrift.protocol.TProtocol;???
  5. ?import?org.apache.thrift.transport.TSocket;???
  6. ?import?org.apache.thrift.transport.TTransport;???
  7. ?import?org.apache.thrift.transport.TTransportException;???
  8. ?import?service.demo.Hello;???
  9. ??
  10. ?public?class?HelloServiceClient?{???
  11. ?/**??
  12. ?????*?调用?Hello?服务?
  13. ?????*?@param?args??
  14. ?????*/???
  15. ????public?static?void?main(String[]?args)?{???
  16. ????????try?{???
  17. ????????????//?设置调用的服务地址为本地,端口为?7911???
  18. ????????????TTransport?transport?=?new?TSocket("localhost",?7911);???
  19. ????????????transport.open();???
  20. ????????????//?设置传输协议为?TBinaryProtocol???
  21. ????????????TProtocol?protocol?=?new?TBinaryProtocol(transport);???
  22. ????????????Hello.Client?client?=?new?Hello.Client(protocol);???
  23. ????????????//?调用服务的?helloVoid?方法??
  24. ????????????client.helloVoid();???
  25. ????????????transport.close();???
  26. ????????}?catch?(TTransportException?e)?{???
  27. ????????????e.printStackTrace();???
  28. ????????}?catch?(TException?e)?{???
  29. ????????????e.printStackTrace();???
  30. ????????}???
  31. ????}???
  32. ?}???
Java代码??【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
  1. package?service.client;???
  2. ?import?org.apache.thrift.TException;???
  3. ?import?org.apache.thrift.protocol.TBinaryProtocol;???
  4. ?import?org.apache.thrift.protocol.TProtocol;???
  5. ?import?org.apache.thrift.transport.TSocket;???
  6. ?import?org.apache.thrift.transport.TTransport;???
  7. ?import?org.apache.thrift.transport.TTransportException;???
  8. ?import?service.demo.Hello;???
  9. ??
  10. ?public?class?HelloServiceClient?{???
  11. ?/**??
  12. ?????*?调用?Hello?服务?
  13. ?????*?@param?args??
  14. ?????*/???
  15. ????public?static?void?main(String[]?args)?{???
  16. ????????try?{???
  17. ????????????//?设置调用的服务地址为本地,端口为?7911???
  18. ????????????TTransport?transport?=?new?TSocket("localhost",?7911);???
  19. ????????????transport.open();???
  20. ????????????//?设置传输协议为?TBinaryProtocol???
  21. ????????????TProtocol?protocol?=?new?TBinaryProtocol(transport);???
  22. ????????????Hello.Client?client?=?new?Hello.Client(protocol);???
  23. ????????????//?调用服务的?helloVoid?方法??
  24. ????????????client.helloVoid();???
  25. ????????????transport.close();???
  26. ????????}?catch?(TTransportException?e)?{???
  27. ????????????e.printStackTrace();???
  28. ????????}?catch?(TException?e)?{???
  29. ????????????e.printStackTrace();???
  30. ????????}???
  31. ????}???
  32. ?}???

代码编写完后运行服务器,再启动客户端调用服务 Hello 的方法 helloVoid,在服务器端的控制台窗口输出“Hello World”(helloVoid 方法实现在控制台打印字符串,没有返回值,所以客户端调用方法后没有返回值输出,读者可以自己尝试其他有返回值方法的调用,其结果可以打印在客户端的控制台窗口 )。

?

Thrift 架构

Thrift 包含一个完整的堆栈结构用于构建客户端和服务器端。下图描绘了 Thrift 的整体架构。


图 1. 架构图

【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
?【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)

如图所示,图中黄色部分是用户实现的业务逻辑,褐色部分是根据 Thrift 定义的服务接口描述文件生成的客户端和服务器端代码框架,红色部分是根据 Thrift 文件生成代码实现数据的读写操作。红色部分以下是 Thrift 的传输体系、协议以及底层 I/O 通信,使用 Thrift 可以很方便的定义一个服务并且选择不同的传输协议和传输层而不用重新生成代码。

Thrift 服务器包含用于绑定协议和传输层的基础架构,它提供阻塞、非阻塞、单线程和多线程的模式运行在服务器上,可以配合服务器 / 容器一起运行,可以和现有的 J2EE 服务器 /Web 容器无缝的结合。

服务端和客户端具体的调用流程如下:


图 2. Server 端启动、服务时序图(查看大图)

【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)


?

该图所示是 HelloServiceServer 启动的过程以及服务被客户端调用时,服务器的响应过程。从图中我们可以看到,程序调用了 TThreadPoolServer 的 serve 方法后,server 进入阻塞监听状态,其阻塞在 TServerSocket 的 accept 方法上。当接收到来自客户端的消息后,服务器发起一个新线程处理这个消息请求,原线程再次进入阻塞状态。在新线程中,服务器通过 TBinaryProtocol 协议读取消息内容,调用 HelloServiceImpl 的 helloVoid 方法,并将结果写入 helloVoid_result 中传回客户端。


图 3. Client 端调用服务时序图(查看大图)

【转】Apache Thrift - 可舒卷的跨语言服务开发框架(代码已修正)
?

该图所示是 HelloServiceClient 调用服务的过程以及接收到服务器端的返回值后处理结果的过程。从图中我们可以看到,程序调用了 Hello.Client 的 helloVoid 方法,在 helloVoid 方法中,通过 send_helloVoid 方法发送对服务的调用请求,通过 recv_helloVoid 方法接收服务处理请求后返回的结果。

?

数据类型

Thrift 脚本可定义的数据类型包括以下几种类型:

读书人网 >Apache

热点推荐