一步步完成thrift rpc示例
- 2019 年 10 月 4 日
- 筆記
本文給出一個在Windows下,使用thrift一步步完成rpc的Java示例。文章主要從如下幾個部分來加以說明:
- 根據thift自動生成程式碼 – 編寫thrif文件,並根據工具在window下自動生成thrif相關程式碼
- 程式碼組成 – 給出Maven工程的模組化結構組成,並在每個模組中一步步實現程式碼
- 測試 – 對編寫的程式碼進行測試,包括Server啟動並綁定服務、Client連接並調用服務
下面就一步步來完成每一個部分~
一、根據thrift自動生成程式碼
1.1 定義服務介面
thrift是一種可伸縮的跨語言服務的發展軟體框架。它結合了功能強大的軟體堆棧的程式碼生成引擎,以建設服務,工作效率和無縫地與C + +,C#,Java,Python和PHP和Ruby結合。
thrift 採用IDL(Interface Definition Language)來定義通用的服務介面,並通過生成不同的語言代理實現來達到跨語言、平台的功能。
hello.thrift
namespace java com.xxx.tutorial.thrift.service service GreetingService { string sayHello(1:string name) }
1.2 產生thrift對應的程式碼
可以訪問【http://thrift.apache.org/download】下載Thrift Compiler for Windows。

本文下載的版本為thrift-0.10.0.exe, 可以通過如下地址下載。
【http://www.apache.org/dyn/closer.cgi?path=/thrift/0.10.0/thrift-0.10.0.exe】
將編寫的xxx.thrift文件,放置在和下載好的thrift-0.10.0.exe同一個目錄之下。

然後執行如下操作即可產生相關程式碼:
thrift-0.10.0.exe -gen java hello.thrift

進入gen-java目錄,我們可以看到根據hello.thrift文件,生成的服務介面文件。

至此,根據thrift文件產生Java程式碼部分就完成了。接下來,要做的就是編寫服務實現、伺服器程式碼以及客戶端調用介面的程式碼等。
二、程式碼組成
2.1 Maven工程結構
thrift-demo這個Maven工程主要包含四個模組,
- thrift-demo-interface – 存放thrift文件產生的程式碼
- thrift-demo-service – 實現服務
- thrift-demo-server – 簡單伺服器
- thrift-demo-client – 簡單的客戶端
pom文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.xxx.tutorial</groupId> <artifactId>thrift-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>thrift-demo-interface</module> <module>thrift-demo-service</module> <module>thrift-demo-server</module> <module>thrift-demo-client</module> </modules></project>

2.2 thrift-demo-interface模組
直接將上述生成的程式碼,拷貝到src/main/java中,如

遇到「紅叉叉」是因為,沒有導入相關的jar包。在該模組下的pom.xml文件中添加相關的依賴包即可:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.xxx.tutorial</groupId> <artifactId>thrift-demo</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>thrift-demo-interface</artifactId> <dependencies> <!-- https://mvnrepository.com/artifact/org.apache.thrift/libthrift --> <dependency> <groupId>org.apache.thrift</groupId> <artifactId>libthrift</artifactId> <version>0.10.0</version> </dependency> </dependencies></project>

服務介面模組搞定,接下來要完成介面的實現。
2.3 thrift-demo-service模組
- 添加thrift-demo-interface依賴
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.xxx.tutorial</groupId> <artifactId>thrift-demo</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>thrift-demo-service</artifactId> <dependencies> <dependency> <groupId>com.xxx.tutorial</groupId> <artifactId>thrift-demo-interface</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> </project>
- 編寫服務介面實現類
package com.xxx.tutorial.thrift.service.impl; import java.util.logging.Logger; import org.apache.thrift.TException; import com.xxx.tutorial.thrift.service.GreetingService; public class GreetingServiceImpl implements GreetingService.Iface { private static final Logger logger = Logger.getLogger(GreetingServiceImpl.class.getName()); public String sayHello(String name) throws TException { logger.info(String.format("調用sayHello方法的參數name = {%s}", name)); return "Hello, " + name; } }

2.4 thrift-demo-server模組
- 添加thrift-demo-service依賴
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.xxx.tutorial</groupId> <artifactId>thrift-demo</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>thrift-demo-server</artifactId> <dependencies> <dependency> <groupId>com.xxx.tutorial</groupId> <artifactId>thrift-demo-service</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> </project>
- 編寫Server類
package com.xxx.tutorial.thrift.server; import java.util.logging.Logger; import org.apache.thrift.TProcessor;import org.apache.thrift.protocol.TBinaryProtocol;import org.apache.thrift.server.TServer;import org.apache.thrift.server.TThreadPoolServer;import org.apache.thrift.transport.TServerSocket;import org.apache.thrift.transport.TTransportException; import com.xxx.tutorial.thrift.service.GreetingService;import com.xxx.tutorial.thrift.service.impl.GreetingServiceImpl; public class GreetingServer { private static final Logger logger = Logger.getLogger(GreetingServer.class.getName()); public static void main(String[] args) { try { TServerSocket serverTransport = new TServerSocket(9090); TBinaryProtocol.Factory proFactory = new TBinaryProtocol.Factory(); /** * 關聯處理器與GreetingService服務實現 */ TProcessor processor = new GreetingService.Processor(new GreetingServiceImpl()); TThreadPoolServer.Args serverArgs = new TThreadPoolServer.Args(serverTransport); serverArgs.processor(processor); serverArgs.protocolFactory(proFactory); TServer server = new TThreadPoolServer(serverArgs); logger.info("Start server on port 9090..."); server.serve(); } catch (TTransportException e) { e.printStackTrace(); } }}

2.5 thrift-demo-client模組
- 添加thrift-demo-interface依賴
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.xxx.tutorial</groupId> <artifactId>thrift-demo</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>thrift-demo-client</artifactId> <dependencies> <dependency> <groupId>com.xxx.tutorial</groupId> <artifactId>thrift-demo-service</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> </project>
- 編寫客戶端調用rpc服務類
package com.xxx.tutorial.thrift.client; import java.util.logging.Logger; 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; import com.xxx.tutorial.thrift.service.GreetingService; public class GreetingClient { private static final Logger logger = Logger.getLogger(GreetingClient.class.getName()); public static void main(String[] args) { try { TTransport transport = new TSocket("127.0.0.1", 9091); transport.open(); TProtocol protocol = new TBinaryProtocol(transport); GreetingService.Client client = new GreetingService.Client(protocol); String name = "Eric"; logger.info("請求參數==>name為" + name); String result = client.sayHello("Eric"); logger.info("返回結果==>為" + result); transport.close(); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); } }}
至此,Maven工程中,4個模組的程式碼就簡單寫完了。 接下來,測試一下。
三、測試
3.1 Server啟動
直接運行GreetingServer.java(其中包含main函數)即可~

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".SLF4J: Defaulting to no-operation (NOP) logger implementationSLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.五月 28, 2017 3:03:27 下午 com.xxx.tutorial.thrift.server.GreetingServer main資訊: Start server on port 9090...
3.2 Client運行
直接運行GreetingClient.java(其中包含main函數)即可。
package com.xxx.tutorial.thrift.client; import java.util.logging.Logger; 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; import com.xxx.tutorial.thrift.service.GreetingService; public class GreetingClient { private static final Logger logger = Logger.getLogger(GreetingClient.class.getName()); public static void main(String[] args) { try { TTransport transport = new TSocket("127.0.0.1", 9091); transport.open(); TProtocol protocol = new TBinaryProtocol(transport); GreetingService.Client client = new GreetingService.Client(protocol); String name = "Eric"; logger.info("請求參數==>name為" + name); String result = client.sayHello("Eric"); logger.info("返回結果==>為" + result); transport.close(); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); } }}

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".SLF4J: Defaulting to no-operation (NOP) logger implementationSLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.五月 28, 2017 3:10:30 下午 com.xxx.tutorial.thrift.client.GreetingClient main資訊: 請求參數==>name為EricReceived 1五月 28, 2017 3:10:30 下午 com.xxx.tutorial.thrift.client.GreetingClient main資訊: 返回結果==>為Hello, Eric
3.3 結果查看
我們可以看到,客戶端調用介面,傳值name為Eric,得到服務端的相應為Hello, Eric。
五月 28, 2017 3:10:30 下午 com.xxx.tutorial.thrift.client.GreetingClient main資訊: 返回結果==>為Hello, Eric

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".SLF4J: Defaulting to no-operation (NOP) logger implementationSLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.五月 28, 2017 3:03:27 下午 com.xxx.tutorial.thrift.server.GreetingServer main資訊: Start server on port 9090...五月 28, 2017 3:10:30 下午 com.xxx.tutorial.thrift.service.impl.GreetingServiceImpl sayHello資訊: 調用sayHello方法的參數name = {Eric}
至此,一個使用thrift完成的簡單rpc示例就完成了。後續會對示例程式碼去完善,並使用更多的IDL中定義的基礎類型,以及多種不同服務類型。