Thrift教程

PRC:遠程服務調用,也是一種網絡協議,使用TCP連接實現,類似HTTP。

Thrift是一種RPC框架,開發人員通過編寫IDL定義兩個服務之間的接口,然後通過Thrift自動生成代碼(包括網絡服務端和客戶端,通信對象),即開發人員只需要編寫業務相關代碼,無需關心數據的通信的過程。

Thrift的底層數據序列化使用的是Google的Protobuf。

結構

Thrift的客戶端和服務端需要配置相關參數:

  • Transport:對網絡的抽象,服務器端需要傳入Socket對象,客戶端需要知道服務端的ip+端口號
  • Protocol:客戶端和服務端相互通信的協議類型
  • Processor:業務處理邏輯,即RPC調用方法的內部實現,只有服務端需要。
    在這裏插入圖片描述

語法

基本數據類型

thrift不支持無符號類型,因爲很多編程語言不存在無符號類型

  • byte:有符號字節
  • i16:16位有符號整數
  • i32:32位有符號整數
  • i64:64位有符號整數
  • double:64位浮點數
  • string:字符串類型
容器類型

集合黃總的元素可以是除了service之外的任何類型

  • list<T>:一系列由T類型的數據組成的有序列表,元素可以重複
  • set<T>:一系列由T類型的數據組成的無序集合,元素不可重複
  • map<K, V>:一個字典結構,key爲K類型,value爲V類型

結構體

結構體對應Java中的對象

struct LoginRequest {  
    1: string name;
    2: string password="thrifty"; // 可以設置參數默認值
}  

枚舉

enum Sex {
    RED,
    BLUE
}

異常

exception RequestException {
     1: i32 code;
    2: string reason;
}

服務

RPC調用的服務,服務中的方法就是RPC調用的方法

service HelloWordService {
	// 傳入參數可以是基本數據類型,或者是自定義的對象struct
	// 返回值可以是基本數據類型,或者是自定義的對象struct
    // 可以拋出異常
     LoginResponse login(1: LoginRequest request) throws (1:RequestException qe); 
 }

類型定義

typedef i32 Integer
typedef i64 Long

全局常量

thrift的常量是全局常量,即thrift會生成 一個常量類,包含所有常量

const i32 MAX_RETRIES_TIME = 10;
// 生成結果
@SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"})
public class Constants {
  public static final int MAX_RETRIES_TIME = 10;
}

命名空間

命名空間即java中的包

namespace <語言> <包的位置>
namespace java com.shine.thrift 

文件包含

文件包含,即導入另外一個thrift文件,在當前thrift文件中可以使用另外一個文件中的變量

include "global.thrift"

註釋

thrift支持多種語言的註釋

#
//
/* */

可選與必選

thrift提供兩個關鍵字required,optional,表示序列化傳輸的時候是否進行未設置值字段的序列化。

  • required:不管有沒有設置字段,序列化的時候都會將字段序列化。(如果沒有設置字段,會序列化字段的初值)
  • optional:如果沒有設置字段,序列化的時候不會將字段序列化,對方訪問該字段時,會獲得字段的初值。
    • 可以縮短報文的長度,提高效率
    • 可以使用isSetXXX()的方法判斷對方是否設置了字段
struct People {
    1: required string name;
    2: optional i32 age;
}

示例

  1. windows端直接下載thrift的exe文件

  2. 編寫login.thrift文件

    • thrift文件是IDL(接口定義語言)文件,通過thrift可以自動生成不同編程語言的代碼
namespace java com.shine.thrift  // 包名

// 消息對象
struct LoginRequest {  
    1: string name;
    2: string password="thrifty";
}  

struct LoginResponse{
    1: string response;
}

// 異常
exception RequestException {  
    1: required i32 code;  
    2: optional string reason;  
}  
  
// 服務  
service Service {  
    LoginResponse login(1: LoginRequest request) throws (1:RequestException qe); // 可能拋出異常。  
    double query(1: i32 request) throws (1:RequestException qe); // 可能拋出異常。 
}
  1. 使用thrift編譯生成java代碼
thrift -gen java test.thrift
  1. 將java代碼放入工程目錄中
  2. 使用maven導入thrift相關包
<!-- https://mvnrepository.com/artifact/org.apache.thrift/libthrift -->
    <dependency>
        <groupId>org.apache.thrift</groupId>
        <artifactId>libthrift</artifactId>
    <version>0.13.0</version>
</dependency>
  1. 實現業務代碼
package thrift.impl;

import org.apache.thrift.TException;
import thrift.*;

public class ServiceImpl implements Service.Iface {
    @Override
    public LoginResponse login(LoginRequest request) throws RequestException, TException {
        String name = request.getName();
        String password = request.getPassword();
        if (name.equals("admin") && password.equals("1234")) {
            return new LoginResponse("成功登陸");
        }
        return new LoginResponse("默認賬號:admin, 默認密碼:1234");
    }

    @Override
    public double query(int number) throws RequestException, TException {
        return number * 1.1;
    }
}
  1. 編寫服務端代碼
package thrift.main;

import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;
import thrift.Service;
import thrift.impl.ServiceImpl;

import java.io.IOException;
import java.net.ServerSocket;

/**
 * 服務端
 */
public class ServerMain {
    public static void main(String[] args) throws IOException, TTransportException {
        // socket編程
        ServerSocket socket = new ServerSocket(8888);

        // thrift Server 傳輸層
        TServerSocket serverTransport = new TServerSocket(socket);

        // Processor封裝了從輸入數據流中讀數據和向數據流中寫數據的操作
        Service.Processor processor = new Service.Processor(new ServiceImpl());

        // 服務器參數 包含傳輸socket 業務處理器
        TServer.Args tServerArgs = new TServer.Args(serverTransport);
        tServerArgs.processor(processor);

        // 服務器
        TServer server = new TSimpleServer(tServerArgs);
        System.out.println("Starting the simple server...");
        server.serve(); // 開始運行
    }
}
  1. 編寫客戶端代碼
package thrift.main;

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 thrift.LoginRequest;
import thrift.LoginResponse;
import thrift.Service;

public class ClientMain {
    public static void main(String[] args) {
        TTransport transport = null;
        try {
            transport = new TSocket("localhost", 8888);

            TProtocol protocol = new TBinaryProtocol(transport);

            // 一個服務對應一個客戶端
            Service.Client client = new Service.Client(protocol);
            transport.open();

            // 訪問login方法
            LoginRequest request = new LoginRequest()
                    .setName("shine")
                    .setPassword("1234");
            LoginResponse loginResponse = client.login(request);// 傳輸請求
            System.out.println(loginResponse.toString());

            // 訪問Query方法
            System.out.println(client.query(11));
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            assert transport != null;
            transport.close();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章