天天看點

Thrift簡明教程

Thrift是個RPC架構,它的目标是為各種流行的開發語言提供便利的RPC調用機制,而不需要使用那些開銷巨大的方式,比如SOAP。

Thrift使用語言中立的服務定義檔案(IDL,接口描述語言),描述資料類型和服務接口。這個檔案會被用作引擎的輸入,編譯器生成代碼為每種支援的語言生成RPC用戶端代碼庫。這種靜态生成的設計讓它非常容易被開發者所使用,而且因為類型驗證都發生在編譯期而非運作期,是以代碼可以很有效率地運作。

Apache Thrift,它采用接口描述語言(IDL)定義并建立服務,支援可擴充的跨語言服務開發,所包含的代碼生成引擎可以在多種語言中,如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等建立高效的、無縫的服務,其傳輸資料采用二進制格式,相對 XML 和 JSON 體積更小,對于高并發、大資料量和多語言的環境更有優勢。

Thrift 服務開發流程,簡單概述如下:

1、定義IDL檔案(xxx.thrift檔案)

2、用xxx.thrift檔案生成Java代碼(服務接口檔案)

3、服務端實作(建立服務):實作服務接口,開啟伺服器

4、用戶端實作(服務消費):引入接口,進行遠端調用。

Thrift 環境

總體感覺,安裝thrift環境,不算簡單,而且很多人不清楚安裝的那些,到底能幹啥?

Mac 安裝thrift可參考:

https://blog.csdn.net/u010827436/article/details/44303897

目前感覺,安裝thrift的目的,就是能夠使用thrift 指令,将xxx.thrift檔案生成Java代碼(僅個人簡單的了解);而生成Java代碼有多種方式,安裝thrift對初學者來說,占據學習的一部分事件,不推薦。

下面快速開始一個簡單的Demo,供初學者對thrift有一個直覺的了解。

1、定義一個IDL接口描述檔案

namespace java com.ljheee.thrift

service QueryService{
    string query(1:string query)
}

           

這個IDL接口描述檔案,采用平台中立、語言中立的方式,描述資料類型和服務接口;即RPC調用過程中,調用方與服務提供方之間通信,傳輸的什麼資料結構、調用的哪個服務接口,是需要在這個.thrift檔案中約定清楚的。

具體檔案含義參考:

如果已經安裝了thrift環境,那麼可以直接使用指令

thrift -gen java demoHello.thrift

生成Java代碼的指令,win、Mac下都相同。指令執行後,會生成一個gen-java檔案夾。

如果還沒有安裝thrift,不要緊,我這裡提供一個下載下傳,先快速上手,預覽全觀。(複制裡面全部内容,建立檔案到對QueryService.java)

https://github.com/ljheee/thrift-demo/blob/master/src/main/java/com/ljheee/thrift/service/QueryService.java

其實由第1步的QueryService.thrift檔案,大概可以看出,定義了一個Java service,裡面有一個方法query(String query)。可以預測,它大概是要定義一個接口:

public interface QueryService {
    public String query(String query) ;
  }
           

事實上,就是這樣。該接口就是服務提供方和服務調用方之間的約定。服務端通過完成接口的具體實作,對外提供服務,用戶端引入該Java接口,進行遠端調用。當然這隻是簡單描述,thrift生成的QueryService接口裡面也有很多它特定的東西,如傳輸協定、序列化方式等。

3、服務端實作(建立服務)

實作服務接口,開啟伺服器。

把第2步生成的Java檔案(QueryService.java),copy到伺服器端工程,注意package不要錯,然後建立類implements QueryService.Iface

package com.ljheee.thrift.service.impl;

import com.ljheee.thrift.service.QueryService;
import org.apache.thrift.TException;

public class QueryServiceImpl implements QueryService.Iface {

    @Override
    public String query(String query) throws TException {
        return "Hello,"+query;
    }
}
           

開啟伺服器,等待用戶端遠端調用

package com.ljheee.thrift;

import com.ljheee.thrift.service.QueryService;
import com.ljheee.thrift.service.impl.QueryServiceImpl;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;

public class Server {

    public static final int SERVER_PORT = 9999;
    public static final String SERVER_IP = "localhost";
    public static final int TIMEOUT = 30000;

    public static void main(String[] args) {
        try {
            System.out.println("QueryService TSimpleServer start ....");

            TProcessor tprocessor = new QueryService.Processor<QueryService.Iface>(new QueryServiceImpl());
            // 簡單的單線程服務模型,一般用于測試
            TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
            TServer.Args tArgs = new TServer.Args(serverTransport);
            tArgs.processor(tprocessor);
            tArgs.protocolFactory(new TBinaryProtocol.Factory());
            // tArgs.protocolFactory(new TCompactProtocol.Factory());
            // tArgs.protocolFactory(new TJSONProtocol.Factory());
            TServer server = new TSimpleServer(tArgs);
            server.serve();
        } catch (Exception e) {
            System.out.println("Server start error!!!");
            e.printStackTrace();
        }
    }
    
}
           

4、用戶端實作(服務消費)

引入生成接口,進行遠端調用。

同樣把第2步生成的Java檔案(QueryService.java),copy到用戶端工程裡面。本系統為示範友善,在同一個工程中放入了server 和Client的類。

package com.ljheee.thrift;

import com.ljheee.thrift.service.QueryService;
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;
import org.apache.thrift.transport.TTransportException;

/**
 * Created by lijianhua04 on 2018/7/27.
 */
public class Client {

    public static final int SERVER_PORT = 9999;
    public static final String SERVER_IP = "localhost";
    public static final int TIMEOUT = 30000;


    public static void main(String[] args) {

        TTransport transport = null;
        try {
            transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
            // 協定要和服務端一緻
            TProtocol protocol = new TBinaryProtocol(transport);
            // TProtocol protocol = new TCompactProtocol(transport);
            // TProtocol protocol = new TJSONProtocol(transport);
            QueryService.Client client = new QueryService.Client(protocol);
            transport.open();
            String result = client.query("ljh");
            System.out.println("Thrify client result =: " + result);
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            if (null != transport) {
                transport.close();
            }
        }
    }
}

           

工程結構目錄

Thrift簡明教程

image.png

https://github.com/ljheee/thrift-demo