精选实例:Thrift 实例教程(Java)

原创 thrift

一、 About Thrift

thrift 是一种可伸缩的跨语言服务的发展软件框架。它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,工作效率和无缝地与 C + +,C#,Java,Python,PHP 和 Ruby 结合。thrift 是 facebook 开发的,我们现在把它作为开源软件使用。thrift 允许你定义一个简单的定义文件中的数据类型和服务接口。以作为输入文件,编译器生成代码用来方便地生成 RPC 客户端和服务器通信的无缝跨编程语言(来自百度百科)。

最初由 facebook 开发用做系统内个语言之间的 RPC 通信 。

2007 年由 facebook 贡献到 apache 基金 ,现在是 apache 下的 opensource 之一。

支持多种语言之间的 RPC 方式的通信:php 语言 client 可以构造一个对象,调用相应的服务方法来调用 java 语言的服务 ,跨越语言的 C/S rpc 调用 。

二、 什么是 Thrift,如何工作

建立一个 java rmi 的流程:

  • 定义一个服务调用接口。
  • server 端:接口实现 — impl的实例 — 注册该服务实现(端口) — 启动服务。
  • client 端:通过 ip、端口、服务名,得到服务,通过接口来调用。
  • rmi 数据传输方式:java 对象序列化。

Thrift 服务

  • 例同 rmi ,需要定义通信接口、实现、注册服务、绑定端口等。
  • 多种语言之间通信。
  • 数据传输走 socket(多种语言均支持),数据再以特定的格式(String ),发送,接收方语言解析。Object ---> String ---> Object

存在问题:编码、解析完全需要自己做,复杂的数据结构可能会导致编码困难。

Thrift 服务 : thrift 的中间编码层

  • java Object -> Thrift Object -> php Object
  • 定义 thrift 的文件,由 thrift 文件(IDL)生成 双方语言的接口、model,在生成的 model 以及接口中会有解码编码的代码。
  • thrift 文件生成代码命令
thrift-xx.exe -gen java TestThrift.thrift // 生成java 代码 
thrift-xx.exe -gen php  TestThrift.thrift // 生成php代码 
thrift-xx.exe -gen py   TestThrift.thrift // 生成python代码 
thrift-xx.exe -gen as3  TestThrift.thrift // 生成as3代码 
thrift-xx.exe -gen cpp  TestThrift.thrift // 生成C++代码

三、 Thrift 安装和依赖

1)安装 thrift:到 thrift 官网下载 exe 文件,然后将文件重命名为 thrift.exe,拷贝到c:\windows目录下,或将 thrift.exe 所在路径加到 path 环境变量中,然后就可以在dos环境下使用了。如:thrift -gen java D:\mywork\javaProject\thriftTest\test.thrift ,输出的java文件默认输出到当前目录下,也可以使用 -o 参数指定输出路径。

linux 下的安装方法可以参考官方详细说明。

2)下载相关依赖包,基于 v0.9.3 测试通过

  1. slf4j-api-1.7.16
  2. slf4j-jdk14-1.7.16
  3. libthrift.jar,或者去 maven 仓库下载。

如果不下载 libthrift.jar 包,将 thrift 源码加入到工程下,那么还需要下载:

  1. httpclient-4.2.1.jar
  2. httpcore-4.2.1.jar
  3. httpmime-4.2.1.jar
  4. servlet-api.jar

四、 基本数据类型和集合类型

bool:布尔类型(true or value),占一个字节
byte:有符号字节
i16:16位有符号整型
i32:32位有符号整型
i64:64位有符号整型
double:64位浮点数
string:未知编码或者二进制的字符串

List<t1>:一系列t1类型的元素组成的有序表,元素可以重复
Set<t1>:一系列t1类型的元素组成的无序表,元素唯一
Map<t1,t2>:key/value对(key的类型是t1且key唯一,value类型是t2)。

五、 Thrift Demo

Thrift IDL 文件

demo.thrift

namespace java com.gemantic.analyse.thrift.index

struct NewsModel{
1:i32 id ;
2:string title;
3:string content;
4:string media_from;
5:string author;
}

service IndexNewsOperatorServices {
string indexNews(1:NewsModel indexNews),
bool deleteArtificiallyNews(1:i32 id)
}

运行 thrift --gen java demo.thrift 后生成 NewsModel.java 模型文件和 IndexNewsOperatorServices.java 服务接口文件,将文件所在包 com.gemantic.analyse.thrift.index 拷贝带 src 下。

服务接口实现

IndexNewsOperatorServicesImpl.java

package com.gemantic.analyse.thrift.index;

import org.apache.thrift.TException;

/**
 * 服务实现
 * @author liuqianfei
 *
 */
public class IndexNewsOperatorServicesImpl implements IndexNewsOperatorServices.Iface{

    @Override
    public boolean deleteArtificiallyNews(int id) throws TException {
        System.out.println("method deleteArtificiallyNews success !!  id is :"+id);
        return true;
    }

    @Override
    public String indexNews(NewsModel indexNews) throws TException {
        System.out.println("method indexNews success !!  data  is :");
        System.out.println(indexNews);
        return "客户端你好,你发送的标题为【" + indexNews.getTitle() + "】的新闻已处理,请耐心等待。";
    }
}

Java 服务端

ThriftServerTest.java

package com.gemantic.analyse.thrift.index;

import java.net.InetSocketAddress;

import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadPoolServer;
import org.apache.thrift.server.TThreadPoolServer.Args;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TServerTransport;
import org.apache.thrift.transport.TTransportFactory;

/**
 * 服务端
 * 
 * @author liuqianfei
 *
 */
public class ThriftServerTest
{
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void main(String[] args)
    {
        IndexNewsOperatorServices.Processor processor
             = new IndexNewsOperatorServices.Processor(new IndexNewsOperatorServicesImpl());
        try
        {
            TServerTransport serverTransport = new TServerSocket(new InetSocketAddress("127.0.0.1", 9981));
            Args trArgs = new Args(serverTransport);
            trArgs.processor(processor);
            // 使用二进制来编码应用层的数据
            trArgs.protocolFactory(new TBinaryProtocol.Factory(true, true));
            // 使用普通的socket来传输数据
            trArgs.transportFactory(new TTransportFactory());
            TServer server = new TThreadPoolServer(trArgs);
            System.out.println("server begin .......................");
            server.serve();
            System.out.println("---------------------------------------");
            server.stop();
        }
        catch (Exception e)
        {
            throw new RuntimeException("index thrift server start failed!!" + "/n" + e.getMessage());
        }
    }
}

Java 客户端

ThriftClientTest.java

package com.gemantic.analyse.thrift.index;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
/**
 * 客户端
 * @author liuqianfei
 *
 */
public class ThriftClientTest
{
    public static void main(String[] args) throws TException
    {
        TTransport transport = new TSocket("127.0.0.1", 9981);
        long start = System.currentTimeMillis();
        TProtocol protocol = new TBinaryProtocol(transport);
        IndexNewsOperatorServices.Client client = new IndexNewsOperatorServices.Client(protocol);

        transport.open();

        // deleteArtificiallyNews
        client.deleteArtificiallyNews(123456);

        // indexNews
        NewsModel newsModel = new NewsModel();
        newsModel.setId(789456);
        newsModel.setTitle("好诗");
        newsModel.setContent("长鬟如云衣似雾,锦茵罗荐承轻步。");
        newsModel.setAuthor("ddc");
        newsModel.setMedia_from("新华08");
        String callback = client.indexNews(newsModel);
        System.out.println("==>" + callback);

        transport.close();

        System.out.println("耗时:" + (System.currentTimeMillis() - start));
        System.out.println("client sucess!");
    }

}

六、 Thrift 协议栈以及各层的使用(java 为例)

FOvaY38.png

  1. model interface : 服务的调用接口以及接口参数 model、返回值 model
  2. Tprotocol 协议层 : 将数据(model)编码、解码
  3. Ttramsport 传输层 : 编码后的数据传输(简单 socket、http)
  4. Tserver : 服务的 Tserver 类型,实现了几种 rpc 调用(单线程、多线程、非阻塞 IO)
如果觉得这对你有用,请随意赞赏,给与作者支持
评论 0
最新评论