一、概述
Thrift是一個軟件框架,用來進行可擴展且跨語言的服務的開發。它結合了功能強大的軟件堆棧和代碼生成引擎,以構建在 C++, Java,
Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 等等編程語言間無縫結合的、高效的服務。
Thrift最初由facebook開發,07年四月開放源碼,08年5月進入apache孵化器。thrift允許你定義一個簡單的定義文件中的數據類型和服務接口。以作爲輸入文件,編譯器生成代碼用來方便地生成RPC客戶端和服務器通信的無縫跨編程語言。【來自百度百科】
官網地址:thrift.apache.org
二、下載依賴(Maven)
1、在pom.xml 中添加如下內容:
<span style="white-space:pre"> </span><dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
三、基本概念以及實現步驟
幾張圖片說明thrift整個流程:
架構圖:
服務端
客戶端
部署圖
注意:圖片來源互聯網
1、數據傳輸協議
TBinaryProtocol : 二進制格式.
TCompactProtocol : 壓縮格式
TJSONProtocol : JSON格式
TSimpleJSONProtocol : 提供JSON只寫協議, 生成的文件很容易通過腳本語言解析
注意:客戶端和服務端的協議要一致。
2、服務端
實現服務處理接口impl
創建TProcessor
創建TServerTransport
創建TProtocol
創建TServer
啓動Server
3、客戶端
創建Transport
創建TProtocol
基於TTransport和TProtocol創建 Client
調用Client的相應方法
四、實例
1、thrift文件創建,並在文件中定義需要的接口方法
namespace java com.jmust.thrift.demo
service HelloWorldService {
string sayHello(1:string username)
}
2、執行thrift-0.9.3.exe生成代碼
thrift-0.9.3.exe -r -gen java ./demoHello.thrift
3、創建一個服務maven項目(shrift-service),將生成的HelloWorldService.java文件複製到自己的項目中,利用maven打包成爲bundle作爲一個服務包,裏面代碼具體是什麼樣子的,我們不需要關心,到時候需要用到的地方,只需要把這個服務包引進去即可使用,下面看看我的pom.xml文件(把該開放出去的package開放出去,該引進來的package引進來)
<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.jmust.thrift</groupId>
<artifactId>thrift-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>thrift-service</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<phase>deploy</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<configuration>
<aggregate>true</aggregate>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.2</version>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.7</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
<Built-By>JMUST</Built-By>
<Bundle-ManifestVersion>2</Bundle-ManifestVersion>
<Bundle-Name>${project.groupId}.${project.ArtifactId}</Bundle-Name>
<Bundle-SymbolicName>${project.groupId}.${project.ArtifactId}</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<Bundle-Vendor>${project.groupId}</Bundle-Vendor>
<Export-Package>com.jmust.thrift.service;version=${project.version}
</Export-Package>
<Import-Package>
javax.annotation,org.slf4j,org.apache.thrift,org.apache.thrift.async,org.apache.thrift.scheme,org.apache.thrift.protocol,org.apache.thrift.server.AbstractNonblockingServer
</Import-Package>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
4、再創建一個實現以上服務maven項目(thrift-demo),pom.xml文件只需要引入
<span style="white-space:pre"> </span><dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>com.jmust.thrift</groupId>
<artifactId>thrift-service</artifactId>
<version>1.0.0</version>
</dependency>
4.1、實現接口Iface
package com.jmust.thrift.impl;
import org.apache.thrift.TException;
import com.jmust.thrift.service.HelloWorldService.Iface;
/**
*
* @author LK
*
*/
public class HelloWorldImpl implements Iface
{
public HelloWorldImpl(){
}
public String sayHello(String username) throws TException {
return "Hi," + username + " welcome to my blog www.jmust.com";
}
}
5、根據協議去實現服務端
5.1、TSimpleServer服務端-----簡單的單線程服務模型,一般用於測試
package com.jmust.thrift.demo;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TServer.Args;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import com.jmust.thrift.impl.HelloWorldImpl;
import com.jmust.thrift.service.HelloWorldService.Iface;
import com.jmust.thrift.service.HelloWorldService.Processor;
/**
* 單線程服務模型,一般用於測試 TSimpleServer服務端
* @author LK
*
*/
public class HelloTSimpleServerDemo {
public static final int SERVER_PORT = 8090;
public void startServer() {
try {
System.out.println("HelloWorld TSimpleServer start ....");
TProcessor tprocessor = new Processor<Iface>(
new HelloWorldImpl());
// 簡單的單線程服務模型,一般用於測試
TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
Args tArgs = new Args(serverTransport);
tArgs.processor(tprocessor);
tArgs.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new TSimpleServer(tArgs);
server.serve();
} catch (Exception e) {
System.out.println("Server start error!!!");
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
HelloTSimpleServerDemo server = new HelloTSimpleServerDemo();
server.startServer();
}
}
5.2、TThreadPoolServer 服務模型 ------線程池服務模型,使用標準的阻塞式IO,預先創建一組線程處理請求
package com.jmust.thrift.demo;
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.server.TThreadPoolServer.Args;
import org.apache.thrift.transport.TServerSocket;
import com.jmust.thrift.impl.HelloWorldImpl;
import com.jmust.thrift.service.HelloWorldService.Iface;
import com.jmust.thrift.service.HelloWorldService.Processor;
/**
* 線程池服務模型,使用標準的阻塞式IO,預先創建一組線程處理請求 TThreadPoolServer 服務模型
* @author LK
*
*/
public class HelloTThreadPoolServerDemo {
public static final int SERVER_PORT = 8090;
public void startServer() {
try {
System.out.println("HelloWorld TThreadPoolServer start ....");
TProcessor tprocessor = new Processor<Iface>(
new HelloWorldImpl());
TServerSocket serverTransport = new TServerSocket(SERVER_PORT);
//TThreadPoolServer 線程池服務模型
Args ttpsArgs = new Args(
serverTransport);
ttpsArgs.processor(tprocessor);
ttpsArgs.protocolFactory(new TBinaryProtocol.Factory());
//線程池服務模型,使用標準的阻塞式IO,預先創建一組線程處理請求。
TServer server = new TThreadPoolServer(ttpsArgs);
server.serve();
} catch (Exception e) {
System.out.println("Server start error!!!");
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
HelloTThreadPoolServerDemo server = new HelloTThreadPoolServerDemo();
server.startServer();
}
}
5.3、TNonblockingServer 服務模型 -------使用非阻塞式IO,服務端和客戶端需要指定 TFramedTransport 數據傳輸的方式
package com.jmust.thrift.demo;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.server.TNonblockingServer;
import org.apache.thrift.server.TNonblockingServer.Args;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;
import com.jmust.thrift.impl.HelloWorldImpl;
import com.jmust.thrift.service.HelloWorldService.Iface;
import com.jmust.thrift.service.HelloWorldService.Processor;
/**
* 使用非阻塞式IO,服務端和客戶端需要指定 TFramedTransport 數據傳輸的方式 TNonblockingServer 服務模型
* @author LK
*
*/
public class HelloTNonblockingServerDemo {
public static final int SERVER_PORT = 8090;
public void startServer() {
try {
System.out.println("HelloWorld TNonblockingServer start ....");
TProcessor tprocessor = new Processor<Iface>(
new HelloWorldImpl());
TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(SERVER_PORT);
Args tnbArgs = new Args(tnbSocketTransport);
tnbArgs.processor(tprocessor);
tnbArgs.transportFactory(new TFramedTransport.Factory());
tnbArgs.protocolFactory(new TCompactProtocol.Factory());
TServer server = new TNonblockingServer(tnbArgs);
server.serve();
} catch (Exception e) {
System.out.println("Server start error!!!");
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
HelloTNonblockingServerDemo server = new HelloTNonblockingServerDemo();
server.startServer();
}
}
5.4、THsHaServer服務模型 -------半同步半異步的服務端模型,需要指定爲: TFramedTransport 數據傳輸的方式
package com.jmust.thrift.demo;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.THsHaServer;
import org.apache.thrift.server.THsHaServer.Args;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TNonblockingServerSocket;
import com.jmust.thrift.impl.HelloWorldImpl;
import com.jmust.thrift.service.HelloWorldService.Iface;
import com.jmust.thrift.service.HelloWorldService.Processor;
/**
* 半同步半異步的服務端模型,需要指定爲: TFramedTransport 數據傳輸的方式 THsHaServer服務模型
* @author LK
*
*/
public class HelloTHsHaServerDemo {
public static final int SERVER_PORT = 8090;
public void startServer() {
try {
System.out.println("HelloWorld THsHaServer start ....");
TProcessor tprocessor = new Processor<Iface>(
new HelloWorldImpl());
TNonblockingServerSocket tnbSocketTransport = new TNonblockingServerSocket(SERVER_PORT);
Args args = new Args(tnbSocketTransport);
args.processor(tprocessor);
args.transportFactory(new TFramedTransport.Factory());
args.protocolFactory(new TBinaryProtocol.Factory());
TServer server = new THsHaServer(args);
server.serve();
} catch (Exception e) {
System.out.println("Server start error!!!");
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
HelloTHsHaServerDemo server = new HelloTHsHaServerDemo();
server.startServer();
}
}
6、客戶端實現
6.1、同步
package com.jmust.thrift.demo;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.apache.thrift.transport.TTransportException;
import com.jmust.thrift.service.HelloWorldService.Client;
/**
*
* @author LK
*
*/
public class HelloClientDemo {
public static final String SERVER_IP = "localhost";
public static final int SERVER_PORT = 8090;
public static final int TIMEOUT = 30000;
/**
*
* @param userName
*/
public void startClient(String userName) {
TTransport transport = null;
try {
//transport = new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
transport = new TFramedTransport(new TSocket(SERVER_IP, SERVER_PORT, TIMEOUT));
// 協議要和服務端一致
TProtocol protocol = new TBinaryProtocol(transport);
//TProtocol protocol = new TCompactProtocol(transport);
// TProtocol protocol = new TJSONProtocol(transport);
Client client = new Client(protocol);
transport.open();
String result = client.sayHello(userName);
System.out.println("Thrify client result =: " + result);
} catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
} finally {
if (null != transport) {
transport.close();
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
HelloClientDemo client = new HelloClientDemo();
client.startClient("lvk");
}
}
6.2、異步
package com.jmust.thrift.demo;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.thrift.TException;
import org.apache.thrift.async.AsyncMethodCallback;
import org.apache.thrift.async.TAsyncClientManager;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.transport.TNonblockingSocket;
import org.apache.thrift.transport.TNonblockingTransport;
import com.jmust.thrift.service.HelloWorldService.AsyncClient;
import com.jmust.thrift.service.HelloWorldService.AsyncClient.sayHello_call;
/**
* 異步客戶端
* @author LK
*
*/
public class HelloAsynClientDemo {
public static final String SERVER_IP = "localhost";
public static final int SERVER_PORT = 8090;
public static final int TIMEOUT = 30000;
/**
*
* @param userName
*/
public void startClient(String userName) {
try {
TAsyncClientManager clientManager = new TAsyncClientManager();
TNonblockingTransport transport = new TNonblockingSocket(SERVER_IP, SERVER_PORT, TIMEOUT);
TProtocolFactory tprotocol = new TCompactProtocol.Factory();
AsyncClient asyncClient = new AsyncClient(tprotocol, clientManager, transport);
System.out.println("Client start .....");
CountDownLatch latch = new CountDownLatch(1);
AsynCallback callBack = new AsynCallback(latch);
System.out.println("call method sayHello start ...");
asyncClient.sayHello(userName, callBack);
System.out.println("call method sayHello .... end");
boolean wait = latch.await(30, TimeUnit.SECONDS);
System.out.println("latch.await =:" + wait);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("startClient end.");
}
public class AsynCallback implements AsyncMethodCallback<sayHello_call>{
private CountDownLatch latch;
public AsynCallback(CountDownLatch latch) {
this.latch = latch;
}
public void onComplete(sayHello_call response) {
System.out.println("onComplete");
try {
// Thread.sleep(1000L * 1);
System.out.println("AsynCall result =:"
+ response.getResult().toString());
} catch (TException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
latch.countDown();
}
}
public void onError(Exception exception) {
System.out.println("onError :" + exception.getMessage());
latch.countDown();
}
}
/**
* @param args
*/
public static void main(String[] args) {
HelloAsynClientDemo client = new HelloAsynClientDemo();
client.startClient("lvk");
}
}
7.、測試步驟
先運行服務端,讓後再運行客戶端,看看是否輸出預計結果。
完畢!