文章目录
Thrift的安装
windows下安装
下载地址:thrift下载地址
比如这里选择thrift-0.9.3.exe
改名为thrift.exe(只是为了命令行使用方便),下载后放到 C:\Thrift(随意),复制路径 C:\Thrift,添加到环境变量Path中即可。
查看版本:
C:\>thrift -version
Thrift version 0.9.3
Linux下安装
下载地址不变
这里选择thrift-0.5.0.tar.gz
,命令行进入该压缩文件所在目录,依次执行以下命令。
tar zxvf thrift-0.5.0.tar.gz
cd thrift-0.5.0
sudo apt-get install automake bison flex g++ git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config
./configure
make
sudo make install
查看安装是否成功:thrift
查看是否安装成功
xxx:~/software/thrift-0.5.0$ thrift
Usage: thrift [options] file
Options:
-version Print the compiler version
-o dir Set the output directory for gen-* packages
(default: current directory)
-I dir Add a directory to the list of directories
searched for include directives
-nowarn Suppress all compiler warnings (BAD!)
-strict Strict compiler warnings on
-v[erbose] Verbose mode
-r[ecurse] Also generate included files
-debug Parse debug trace to stdout
--gen STR Generate code with a dynamically-registered generator.
STR has the form language[:key1=val1[,key2,[key3=val3]]].
Keys and values are options passed to the generator.
Many options will not require values.
Available generators (and options):
as3 (AS3):
bindable: Add [bindable] metadata to all the struct classes.
Thrift的使用
Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook开发捐给apache的。
接下来通过简单的远程过程调用案例来进行介绍
编写IDL文件
该框架是一个典型的C/S结构,即客户端/服务端结构;客户端和服务端可以使用不同的语言进行开发,既然这样那么肯定有一种中间语言来连接客户端和服务端,这种语言即为IDL
IDL为接口定义(或者说描述)语言的简写,在thrift中就是指的*.thrift文件,有自己的一套语法,但是很简单。使用idea的时候,创建了该文件会提示安装插件,让开发更简单。
namespace java com.scu.thrift.shared
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string String
struct Goods {
1: optional long id,
2: optional String name,
3: optional double price,
4: optional String desc
}
exception GoodsException {
1: int code,
2: String message,
3: long date
}
service GoodsService {
Goods getGoodsById(1: required long id) throws (1: GoodsException e),
int saveGoods(1: required Goods goods) throws (1: GoodsException e)
}
命名空间: namespace
相当于java中的package
namespace java com.scu.thrift.shared` 表示生成java文件,同时会放在com.scu.thrift.shared目录下;
基本数据类型:
byte: 有符号字节
i16: 16位有符号字节,相当于java的short
i32: 32位有符号字节,相当于java的int
i64: 64位有符号字节, 相当于java的long
double: 64位浮点数,相当于java的double
string: 字符串类型
bool: 相当于java的boolean
此外还有容器类型:list,set,map和java一样
类型定义:typedef
typedef
: 顾名思义,定义类型,typedef i32 int
表示将i32命名为int, 方便后续使用,直接可以使用int来代替i32。
结构体类型: struct
相当于java的类
struct Goods {
1: optional long id,
2: optional String name,
3: optional double price,
4: optional String desc
}
其中的每个属性使用序号1,2,3,…进行标注,接着是参数类型和参数名称,每行使用逗号进行分割,最后一行不需要。optional表示可选,默认就是optional。
枚举类型: enum
enum Size {
BIG,
SMALL
}
异常类型:exception
也是和java类型的
exception GoodsException {
1: int code,
2: String message,
3: long date
}
规则和结构体类型一样,需要注意的是没有日期类型,通常使用时间戳来表示,或者也可以使用string类型。
服务类型:service
相当于java中的interface,其中写的是一个个的抽象方法
service GoodsService {
Goods getGoodsById(1: required long id) throws (1: GoodsException e),
int saveGoods(1: required Goods goods) throws (1: GoodsException e)
}
这里定义了两个方法,required表示必传,不管是异常列表还是参数列表,同样需要使用序号。
文件包含:include
相当于java中的import
include com.scu.data.thrift
注释
使用 //,#,/**/
商品查询和添加案例
创建工程thrift-parent,打包方式为pom,删除掉src文件夹(个人习惯,毕竟父工程也不会去写代码,这里仅仅是管理依赖),最后天津 thrift的依赖。
<packaging>pom</packaging>
<groupId>com.scu</groupId>
<artifactId>thrift-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
</dependencies>
在thrift-parent项目下创建三个模块,
open-shared:管理公共资源,比如将idl文件生成的java文件都放在这,打成jar包,那么服务提供方和调用方引入依赖就可以使用了。
open-web: 服务调用方
open-service:服务提供方
最终thrift-parent的 pom.xml文件如下
<?xml version="1.0" encoding="UTF-8"?>
<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>
<packaging>pom</packaging>
<modules>
<module>open-shared</module>
<module>open-web</module>
<module>open-service</module>
</modules>
<groupId>com.scu</groupId>
<artifactId>thrift-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
</dependencies>
</project>
在open-shared的src下编写thrift/open.thrift文件
namespace java com.scu.thrift.shared
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string String
struct Goods {
1: optional long id,
2: optional String name,
3: optional double price,
4: optional String desc
}
exception GoodsException {
1: int code,
2: String message,
3: long date
}
service GoodsService {
Goods getGoodsById(1: required long id) throws (1: GoodsException e),
int saveGoods(1: required Goods goods) throws (1: GoodsException e)
}
命令行进入到该目录,执行命令
C:\Users\mi\workspaces\thrift-parent>cd open-shared
C:\Users\mi\workspaces\thrift-parent\open-shared>thrift --gen java src/thrift/open.thrift
C:\Users\mi\workspaces\thrift-parent\open-shared>
此时在src下可以看到生产的目录结构和java文件
将open-shared进行安装 命令:mvn install
;在open-web,open-service中引入open-shared依赖
编写服务端
服务端指的是提供商场服务的一端,即open-service
首先需要实现接口:
public class GoodsServiceImpl implements GoodsService.Iface {
@Override
public Goods getGoodsById(long id) throws GoodsException, TException {
Goods goods = new Goods().setId(id).setName("mi").setPrice(3699.0).setDesc("第一款5G手机");
System.out.println("查找商品:" + goods);
return goods;
}
@Override
public int saveGoods(Goods goods) throws GoodsException, TException {
System.out.println("保存商品:" + goods);
return (int)goods.getId();
}
}
启动服务:
public class ThriftServer {
public static void main(String[] args) throws TTransportException {
TNonblockingServerSocket socket = new TNonblockingServerSocket(8081);// 创建非阻塞socket
THsHaServer.Args arg = new THsHaServer.Args(socket).minWorkerThreads(2).maxWorkerThreads(4); // 设置最小最大工作线程
GoodsService.Processor<GoodsServiceImpl> processor = new GoodsService.Processor<>(new GoodsServiceImpl()); // 绑定服务
// 会把二级制进行进一步压缩 这种传输格式用的最多
arg.protocolFactory(new TCompactProtocol.Factory()); // TProtocol传输数据的格式也是一种协议
arg.transportFactory(new TFramedTransport.Factory()); // 传输
arg.processorFactory(new TProcessorFactory(processor)); // 服务与服务端绑定,所以PersonServiceImpl的输出在服务端
TServer server =new THsHaServer(arg); // 半同步半异步
server.serve(); // 死循环,异步非阻塞
}
}
编写客户端
即open-web,会进行服务的调用,查询和保存商品
public class ThriftClient {
public static void main(String[] args) throws Exception {
TTransport transport = new TFramedTransport(new TSocket("localhost", 8081), 1000);
TProtocol protocol = new TCompactProtocol(transport);
GoodsService.Client client =new GoodsService.Client(protocol);
transport.open();
Goods goods = client.getGoodsById(10086);
System.out.println(goods);
System.out.println("------------------------");
int id = client.saveGoods(new Goods().setId(10010).setName("iphone").setPrice(5499.0).setDesc("玩游戏还是很舒服的"));
System.out.println(id);
}
}
查看结果
先运行服务端,再运行客户端。
服务端窗口输出:
查找商品:Goods(id:10086, name:mi, price:3699.0, desc:第一款5G手机)
保存商品:Goods(id:10010, name:iphone, price:5499.0, desc:玩游戏还是很舒服的)
客户端窗口输出:
Goods(id:10086, name:mi, price:3699.0, desc:第一款5G手机)
------------------------
10010
接口简单介绍
官网的架构如下:
Thrift的数据传输格式:
- TBinaryProtocol: 二进制格式;
- TCompactProtocol: 在二进制格式上进行进一步压缩, 大部分场景推荐这个;
- TJSONProtocol: JSON格式;
- TSimpleJSONProtocol: JSON只写协议,即编码后难以解码,一般不会使用到。
thrift的数据传输方式:
- TFramedTransport: 以 frame(帧)为单位进行传输,在非阻塞式服务中应用;
- TFileTransport: 以文件的形式进行传输;
- TMemoryTransport: 将内存用于IO的形式,java中简单使用了ByteArrayOutputStream来进行实现。
thrift支持的服务模型
- TSimpleServer: 简单的单线程服务模型,常用于测试;
- TThreadPoolServer: 多线程服务模型,使用了标准的阻塞式IO;
- TNonblockingServer: 多线程服务模型,使用了非阻塞式IO(需要配合TFramedTransport使用);
- THsHaServer:使用半同步半异步的处理模式,半异步用来处理IO事件(accept/read/write IO),半同步用于handler对rpc的同步处理。该方式是引入了线程池的。