[Thrift]Apache Thrift入门Java实例

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/52606287 1. 概述Apache Thrift 是 Facebook 实现的一种高效的、支持多种编程语言的远程服务调用的框架。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/52606287
1. 概述

Apache Thrift 是 Facebook 实现的一种高效的、支持多种编程语言的远程服务调用的框架。本文将从 Java 开发人员角度详细介绍 Apache Thrift 的架构、开发和部署,并且针对不同的传输协议和服务类型给出相应的 Java 实例,同时详细介绍 Thrift 异步客户端的实现,最后提出使用 Thrift 需要注意的事项。

目前流行的服务调用方式有很多种,例如基于 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 的使用,并且提供丰富的实例代码加以解释说明,帮助使用者快速构建服务。

2. Maven依赖

Maven地址:http://mvnrepository.com/artifact/org.apache.thrift/libthrift

在这里,我使用的是0.9.3版本:

 
 
  1. <!-- https://mvnrepository.com/artifact/org.apache.thrift/libthrift -->
  2. <dependency>
  3.    <groupId>org.apache.thrift</groupId>
  4.    <artifactId>libthrift</artifactId>
  5.    <version>0.9.3</version>
  6. </dependency>

3. 安装 Thrift compiler

在编译.thrift文件时需要用到

 
 
  1. xiaosi@Qunar:/opt/apache-flume-1.6.0-bin$ sudo apt-get install thrift-compiler
  2. [sudo] xiaosi 的密码:
  3. 正在读取软件包列表... 完成
  4. 正在分析软件包的依赖关系树      
  5. 正在读取状态信息... 完成      
  6. 下列【新】软件包将被安装:
  7.  thrift-compiler
  8. 升级了 0 个软件包,新安装了 1 个软件包,要卸载 0 个软件包,有 162 个软件包未被升级。
  9. 需要下载 819 kB 的软件包。
  10. 解压缩后会消耗掉 2,944 kB 的额外空间。
  11. 获取:1 http://cn.archive.ubuntu.com/ubuntu/ wily/universe thrift-compiler amd64 0.9.1-2 [819 kB]
  12. 下载 819 kB,耗时 0 (982 kB/s)        
  13. 正在选中未选择的软件包 thrift-compiler
  14. (正在读取数据库 ... 系统当前共安装有 273041 个文件和目录。)
  15. 正准备解包 .../thrift-compiler_0.9.1-2_amd64.deb  ...
  16. 正在解包 thrift-compiler (0.9.1-2) ...
  17. 正在处理用于 man-db (2.7.4-1) 的触发器 ...
  18. 正在设置 thrift-compiler (0.9.1-2) ...

4. 创建Thrift文件

在安装Thrift编译器之后,我们需要创建一个.thrift文件,在这里我们在main文件夹下创建calculator.thrift文件。

这个文件是一个接口定义(服务)文件。这些服务会被服务器端实现,被客户端调用。服务器端和客户端下面会讲解到。

 
 
  1. // defines the namespace
  2. namespace java com.sjf.open
  3. service CalculatorService {
  4.    i32 add(1:i32 num1, 2:i32 num2)
  5.    i32 minus(1:i32 num1, 2:i32 num2)
  6.    i32 multi(1:i32 num1, 2:i32 num2)
  7.    i32 divi(1:i32 num1, 2:i32 num2)
  8. }

其中定义了CalculatorService服务的4个方法,每个方法包含一个方法名,参数列表和返回类型。每个参数包括参数序号,参数类型以及参数名(1:i32 num1)。 Thrift 是对 IDL(Interface Definition Language) 描述性语言的一种具体实现。因此,以上的服务描述文件使用 IDL 语法编写。使用 Thrift 工具编译 Calculator.thrift,就会生成相应的 CalculatorService.java 文件。namespace 定义了命名空间,在java中为包,在这里我们会在com.sjf.open包下生成CalculatorService.java 文件。

5. 编译Thrift文件

Thrift编译器会将thrift文件编译成Java代码。使用下面的命令编译.thrift文件:

 
 
  1. thrift --gen <language> <Thrift filename>

在我们例子中,命令为:

 
 
  1. xiaosi@Qunar:~/code/open/openDiary/ThriftDemo/src/main$ thrift --gen java calculator.thrift

编译之后,会在gen-java文件夹下创建com.sjf.open包,并在包下生成CalculatorService.java 文件。

该文件包含了在 Calculator.thrift 文件中描述的服务 CalculatorService 的接口定义,即 CalculatorService.Iface 接口,以及服务调用的底层通信细节,包括客户端的调用逻辑 CalculatorService.Client 以及服务器端的处理逻辑 CalculatorService.Processor,用于构建客户端和服务器端的功能。

6. 创建Service Handler类

Service handler 类必须实现 CalculatorService.Iface接口。Handler类是接口的实现类。

 
 
  1. package com.sjf.open;
  2. import org.apache.thrift.TException;
  3. /**
  4. * Created by xiaosi on 16-9-20.
  5. */
  6. public class CalculatorHandler implements CalculatorService.Iface{
  7.    public int add(int num1, int num2) throws TException {
  8.        return num1 + num2;
  9.    }
  10.    public int minus(int num1, int num2) throws TException {
  11.        return num1 - num2;
  12.    }
  13.    public int multi(int num1, int num2) throws TException {
  14.        return num1 * num2;
  15.    }
  16.    public int divi(int num1, int num2) throws TException {
  17.        if(num2 == 0){
  18.            throw new RuntimeException("分母不能为0");
  19.        }
  20.        return num1 / num2;
  21.    }
  22. }

7. 创建服务器端CalculatorServer

创建服务器端实现代码,将 CalculatorHandler 作为具体的处理器传递给 Thrift 服务器。

 
 
  1. package com.sjf.open;
  2. import org.apache.thrift.server.TServer;
  3. import org.apache.thrift.server.TSimpleServer;
  4. import org.apache.thrift.transport.TServerSocket;
  5. import org.apache.thrift.transport.TServerTransport;
  6. /**
  7. * Created by xiaosi on 16-9-20.
  8. */
  9. public class CalculatorServer {
  10.    private static int port = 9090;
  11.    private static CalculatorHandler handler;
  12.    private static CalculatorService.Processor processor;
  13.    /**
  14.     * 启动服务器
  15.     * @param processor
  16.     */
  17.    public static void start(CalculatorService.Processor processor){
  18.        try {
  19.            TServerTransport serverTransport = new TServerSocket(port);
  20.            TServer server = new TSimpleServer(new TServer.Args(serverTransport).processor(processor));
  21.            // Use this for a multithreaded server
  22.            // TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport).processor(processor));
  23.            System.out.println("Starting the simple server...");
  24.            server.serve();
  25.        } catch (Exception e) {
  26.            e.printStackTrace();
  27.        }
  28.    }
  29.    public static void main(String[] args) {
  30.        handler = new CalculatorHandler();
  31.        processor = new CalculatorService.Processor(handler);
  32.        start(processor);
  33.    }
  34. }

8. 创建客户端CalculatorClient

创建客户端实现代码,调用 CalculatorService.client 访问服务端的逻辑实现。

 
 
  1. package com.sjf.open;
  2. import com.google.common.base.Objects;
  3. import org.apache.thrift.TException;
  4. import org.apache.thrift.protocol.TBinaryProtocol;
  5. import org.apache.thrift.protocol.TProtocol;
  6. import org.apache.thrift.transport.TSocket;
  7. import org.apache.thrift.transport.TTransport;
  8. import org.apache.thrift.transport.TTransportException;
  9. /**
  10. * Created by xiaosi on 16-9-20.
  11. */
  12. public class CalculatorClient {
  13.    private static int port = 9090;
  14.    private static String ip = "localhost";
  15.    private static CalculatorService.Client client;
  16.    private static TTransport transport;
  17.    /**
  18.     * 创建 TTransport
  19.     * @return
  20.     */
  21.    public static TTransport createTTransport(){
  22.        TTransport transport = new TSocket(ip, port);
  23.        return transport;
  24.    }
  25.    /**
  26.     * 开启 TTransport
  27.     * @param transport
  28.     * @throws TTransportException
  29.     */
  30.    public static void openTTransport(TTransport transport) throws TTransportException {
  31.        if(Objects.equal(transport, null)){
  32.            return;
  33.        }
  34.        transport.open();
  35.    }
  36.    /**
  37.     * 关闭 TTransport
  38.     * @param transport
  39.     */
  40.    public static void closeTTransport(TTransport transport){
  41.        if(Objects.equal(transport, null)){
  42.            return;
  43.        }
  44.        transport.close();
  45.    }
  46.    /**
  47.     * 创建客户端
  48.     * @return
  49.     */
  50.    public static CalculatorService.Client createClient(TTransport transport){
  51.        if(Objects.equal(transport, null)){
  52.            return null;
  53.        }
  54.        TProtocol protocol = new TBinaryProtocol(transport);
  55.        if(Objects.equal(protocol, null)){
  56.            return null;
  57.        }
  58.        CalculatorService.Client client = new CalculatorService.Client(protocol);
  59.        return client;
  60.    }
  61.    public static void main(String[] args) {
  62.        try {
  63.            // 创建 TTransport
  64.            transport = createTTransport();
  65.            // 开启 TTransport
  66.            openTTransport(transport);
  67.            // 创建客户端
  68.            client = createClient(transport);
  69.            // 调用服务
  70.            if(Objects.equal(client, null)){
  71.                System.out.println("创建客户端失败...");
  72.                return;
  73.            }
  74.            System.out.println(client.add(100, 200));
  75.        } catch (TException e) {
  76.            e.printStackTrace();
  77.        }
  78.        finally {
  79.            // 关闭 TTransport
  80.            closeTTransport(transport);
  81.        }
  82.    }
  83. }

9. 运行

完成结构图:


运行服务端代码(CalculatorServer)将会看到下面的输出:

 
 
  1. Starting the simple server...

然后运行客户端代码(CalculatorClient),将会看到如下输出:

 
  
  1. 300
我们在客户端中调用了add(100,200),故正确结果为300。
10. 代码连接

https://github.com/sjf0115/OpenDiary/tree/master/ThriftDemo


参考连接:

http://thrift.apache.org/

http://thrift.apache.org/




目录
相关文章
|
1月前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第17天】本文详细介绍了Java编程中Map的使用,涵盖Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的并发处理和性能优化技巧,适合初学者和进阶者学习。
50 3
|
12天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
18天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
24天前
|
存储 安全 Java
🌟Java零基础-反序列化:从入门到精通
【10月更文挑战第21天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
65 5
|
22天前
|
安全 Java 调度
Java中的多线程编程入门
【10月更文挑战第29天】在Java的世界中,多线程就像是一场精心编排的交响乐。每个线程都是乐团中的一个乐手,他们各自演奏着自己的部分,却又和谐地共同完成整场演出。本文将带你走进Java多线程的世界,让你从零基础到能够编写基本的多线程程序。
32 1
|
28天前
|
Java 数据处理 开发者
Java多线程编程的艺术:从入门到精通####
【10月更文挑战第21天】 本文将深入探讨Java多线程编程的核心概念,通过生动实例和实用技巧,引导读者从基础认知迈向高效并发编程的殿堂。我们将一起揭开线程管理的神秘面纱,掌握同步机制的精髓,并学习如何在实际项目中灵活运用这些知识,以提升应用性能与响应速度。 ####
45 3
|
30天前
|
Java
Java中的多线程编程:从入门到精通
本文将带你深入了解Java中的多线程编程。我们将从基础概念开始,逐步深入探讨线程的创建、启动、同步和通信等关键知识点。通过阅读本文,你将能够掌握Java多线程编程的基本技能,为进一步学习和应用打下坚实的基础。
|
1月前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第19天】本文介绍了Java编程中重要的数据结构——Map,通过问答形式讲解了Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的使用和性能优化技巧,适合初学者和进阶者学习。
45 4
|
30天前
|
Java
通过Java代码解释成员变量(实例变量)和局部变量的区别
本文通过一个Java示例,详细解释了成员变量(实例变量)和局部变量的区别。成员变量属于类的一部分,每个对象有独立的副本;局部变量则在方法或代码块内部声明,作用范围仅限于此。示例代码展示了如何在类中声明和使用这两种变量。
|
30天前
|
Java
[Java]Socket套接字(网络编程入门)
本文介绍了基于Java Socket实现的一对一和多对多聊天模式。一对一模式通过Server和Client类实现简单的消息收发;多对多模式则通过Server类维护客户端集合,并使用多线程实现实时消息广播。文章旨在帮助读者理解Socket的基本原理和应用。
23 1

推荐镜像

更多
下一篇
无影云桌面