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




目录
相关文章
|
17天前
|
JSON NoSQL Java
Redis入门到通关之Java客户端SpringDataRedis(RedisTemplate)
Redis入门到通关之Java客户端SpringDataRedis(RedisTemplate)
33 0
|
2天前
|
SQL Java 关系型数据库
零基础轻松入门Java数据库连接(JDBC)
零基础轻松入门Java数据库连接(JDBC)
8 0
|
2天前
|
存储 安全 算法
Java一分钟之-Java集合框架入门:List接口与ArrayList
【5月更文挑战第10天】本文介绍了Java集合框架中的`List`接口和`ArrayList`实现类。`List`是有序集合,支持元素重复并能按索引访问。核心方法包括添加、删除、获取和设置元素。`ArrayList`基于动态数组,提供高效随机访问和自动扩容,但非线程安全。文章讨论了三个常见问题:索引越界、遍历时修改集合和并发修改,并给出避免策略。通过示例代码展示了基本操作和安全遍历删除。理解并正确使用`List`和`ArrayList`能提升程序效率和稳定性。
7 0
|
4天前
|
Java API 开发工具
java与Android开发入门指南
java与Android开发入门指南
11 0
|
4天前
|
Java
Java一分钟之-类与对象:面向对象编程入门
【5月更文挑战第8天】本文为Java面向对象编程的入门指南,介绍了类与对象的基础概念、常见问题及规避策略。文章通过代码示例展示了如何定义类,包括访问修饰符的适当使用、构造器的设计以及方法的封装。同时,讨论了对象创建与使用时可能遇到的内存泄漏、空指针异常和数据不一致等问题,并提供了相应的解决建议。学习OOP需注重理论与实践相结合,不断编写和优化代码。
26 1
|
5天前
|
数据采集 机器学习/深度学习 Java
数据猎手:使用Java和Apache HttpComponents库下载Facebook图像
本文介绍了如何使用Java和Apache HttpComponents库从Facebook获取图像数据。通过设置爬虫代理IP以避免限制,利用HttpClient发送请求,解析HTML找到图像链接,然后下载并保存图片。提供的Java代码示例展示了实现过程,包括创建代理配置、线程池,以及下载图片的逻辑。注意,实际应用需根据Facebook页面结构进行调整。
数据猎手:使用Java和Apache HttpComponents库下载Facebook图像
|
5天前
|
Java 编译器 对象存储
java一分钟之Java入门:认识JDK与JVM
【5月更文挑战第7天】本文介绍了Java编程的基础——JDK和JVM。JDK是包含编译器、运行时环境、类库等的开发工具包,而JVM是Java平台的核心,负责执行字节码并实现跨平台运行。常见问题包括版本不匹配、环境变量配置错误、内存溢出和线程死锁。解决办法包括选择合适JDK版本、正确配置环境变量、调整JVM内存参数和避免线程死锁。通过代码示例展示了JVM内存管理和基本Java程序结构,帮助初学者更好地理解JDK和JVM在Java编程中的作用。
18 0
|
12天前
|
设计模式 算法 安全
Java多线程编程实战:从入门到精通
【4月更文挑战第30天】本文介绍了Java多线程编程的基础,包括线程概念、创建线程(继承`Thread`或实现`Runnable`)、线程生命周期。还讨论了线程同步与锁(同步代码块、`ReentrantLock`)、线程间通信(等待/通知、并发集合)以及实战技巧,如使用线程池、线程安全设计模式和避免死锁。性能优化方面,建议减少锁粒度和使用非阻塞算法。理解这些概念和技术对于编写高效、可靠的多线程程序至关重要。
|
13天前
|
算法 Java 大数据
Java从入门到精通学习报告
Java从入门到精通学习报告
20 1
|
14天前
|
数据采集 存储 前端开发
Nutch库入门指南:利用Java编写采集程序,快速抓取北京车展重点车型
2024年北京车展凸显电动车全球热度,中国引领市场,展出117台全球首发车,包括30台跨国公司电动车。借助Nutch库抓取汽车网站数据,分析电动车市场趋势。通过配置代理和多线程爬虫,高效收集新车信息,助力理解市场动态,推动可持续交通发展。
Nutch库入门指南:利用Java编写采集程序,快速抓取北京车展重点车型

推荐镜像

更多