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;
}
示例
-
windows端直接下載thrift的exe文件
-
編寫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); // 可能拋出異常。
}
- 使用thrift編譯生成java代碼
thrift -gen java test.thrift
- 將java代碼放入工程目錄中
- 使用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>
- 實現業務代碼
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;
}
}
- 編寫服務端代碼
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(); // 開始運行
}
}
- 編寫客戶端代碼
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();
}
}
}