惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
爱范儿
爱范儿
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Y
Y Combinator Blog
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
Martin Fowler
Martin Fowler
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
M
MIT News - Artificial intelligence
博客园 - Franky
V
Visual Studio Blog
I
InfoQ
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
博客园 - 司徒正美
L
LangChain Blog

Jark's Blog

Flink 1.16:Hive SQL 如何平迁到 Flink SQL Flink CDC 如何简化实时数据入湖入仓 基于 Flink SQL 构建流批一体的 ETL 数据集成 Nexmark: 如何设计一个流计算基准测试? Demo:基于 Flink SQL 构建流式应用 Flink 1.9 实战:使用 SQL 读取 Kafka 并写入 MySQL Flink SQL 编程实践 如何从小白成长为 Apache Committer? 聊聊Blink开源和Flink社区近况 Flink 小贴士 (7): 4个步骤,让 Flink 应用达到生产状态 Flink 小贴士 (6): 使用 Broadcast State 的 4 个注意事项 Flink 小贴士 (5): Savepoint 和 Checkpoint 的 3 个不同点 Flink 小贴士 (4): 如何选择状态后端 Flink 小贴士 (3): 轻松理解 Watermark 一文了解 Apache Flink 核心技术 Flink 零基础实战教程:如何计算实时热门商品 5分钟从零构建第一个 Flink 应用 Flink 小贴士 (2):Flink 如何管理 Kafka 消费位点 Flink小贴士 (1):确定Flink作业所需资源大小时要考虑的6件事 Flink在美团的实践与应用 我在阿里的这两年 Flink 原理与实现:Aysnc I/O Flink 原理与实现:Table & SQL API Flink 原理与实现:Session Window Flink 原理与实现:Window 机制 Flink 原理与实现:数据流上的类型和操作 Flink 原理与实现:如何生成 JobGraph Flink 原理与实现:理解 Flink 中的计算资源 Flink 原理与实现:如何生成 StreamGraph Flink 原理与实现:架构和拓扑概览
Thrift 实践
WuChong · 2015-10-07 · via Jark's Blog

发表于   |   分类于 程序设计   |  

上一篇文章我们了解了thrift的概念以及类型系统,本文我们通过一个简单的实例来更深入地了解thrift的使用。我们的实例非常简单,就是实现一个登录注册功能,其用户名密码缓存在内存中。

编写thrift文件

我们编写一个account.thrift的文件。

namespace java me.wuchong.thrift.generated

enum Operation{
LOGIN = 1,
REGISTER = 2
}

struct Request{
1: string name,
2: string password,
3: Operation op
}

exception InvalidOperation{
1: i32 code,
2: string reason
}

service Account{
string doAction(1: Request request) throws (1: InvalidOperation e);
}

然后在命令行下运行如下命令:

thrift --gen java account.thrift

则会在当前目录生成gen-java目录,该目录下会按照namespace定义的路径名一次一层层生成文件夹,如下图所示,在指定的包路径下生成了4个类。

服务实现

到此为止,thrift已经完成了其工作。接下来我们需要做的就是实现Account接口里的具体逻辑。我们创建一个AccountService类,实现Account.Iface接口。逻辑非常简单,将用户账户信息缓存在内存中,实现登录注册的功能,并且对一些非法输入状况抛出异常。

package me.wuchong.thrift.impl;

import me.wuchong.thrift.generated.Account;
import me.wuchong.thrift.generated.InvalidOperation;
import me.wuchong.thrift.generated.Operation;
import me.wuchong.thrift.generated.Request;

import java.util.HashMap;
import java.util.Map;

/**
* Created by wuchong on 15/10/7.
*/
public class AccountService implements Account.Iface {
private static Map<String, String> accounts = new HashMap<>();

@Override
public String doAction(Request request) throws InvalidOperation {
String name = request.getName();
String pass = request.getPassword();
Operation op = request.getOp();

System.out.println(String.format("Get request[name:%s, pass:%s, op:%d]", name, pass, op.getValue()));

if (name == null || name.length() == 0){
throw new InvalidOperation(100, "param name should not be empty");
}

if (op == Operation.LOGIN) {
String password = accounts.get(name);
if (password != null && password.equals(pass)) {
return "Login success!! Hello " + name;
} else {
return "Login failed!! please check your username and password";
}
} else if (op == Operation.REGISTER) {
if (accounts.containsKey(name)) {
return String.format("The username '%s' has been registered, please change one.", name);
} else {
accounts.put(name, pass);
return "Register success!! Hello " + name;
}
} else {
throw new InvalidOperation(101, "unknown operation: " + op.getValue());
}
}
}

启动服务端和客户端

我们实现了服务的具体逻辑,接下来需要启动该服务。这里我们需要用到thrift的依赖包。在pom.xml中加入对thrift的依赖。

<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.2</version>
</dependency>

注:如果你的依赖中没有加入slf4j的实现,则需要加上slf4j-log4j12或者logback的依赖,因为thrift有用到slf4j

启动服务的实现如下:

package me.wuchong.thrift.impl;

import me.wuchong.thrift.generated.Account;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;

/**
* Created by wuchong on 15/10/7.
*/
public class AccountServer {
public static void main(String[] args) throws Exception {
TServerSocket socket = new TServerSocket(9999);
Account.Processor processor = new Account.Processor<>(new AccountService());
TServer server = new TSimpleServer(new TServer.Args(socket).processor(processor));
System.out.println("Starting the Account server...");
server.serve();
}
}

运行之后,可以在控制台看到输出:

Starting the Account server...

目前服务已经启动,则在客户端就可以进行RPC调用了。启动客户端的代码如下:

package me.wuchong.thrift.impl;

import me.wuchong.thrift.generated.Account;
import me.wuchong.thrift.generated.InvalidOperation;
import me.wuchong.thrift.generated.Operation;
import me.wuchong.thrift.generated.Request;
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;

/**
* Created by wuchong on 15/10/7.
*/
public class AccountClient {
public static void main(String[] args) throws TException {
TTransport transport = new TSocket("localhost", 9999);
transport.open(); //建立连接

TProtocol protocol = new TBinaryProtocol(transport);
Account.Client client = new Account.Client(protocol);

//第一个请求, 登录 wuchong 帐号
Request req = new Request("wuchong", "1234", Operation.LOGIN);
request(client, req);

//第二个请求, 注册 wuchong 帐号
req.setOp(Operation.REGISTER);
request(client, req);

//第三个请求, 登录 wuchong 帐号
req.setOp(Operation.LOGIN);
request(client, req);

//第四个请求, name 为空的请求
req.setName("");
request(client, req);

transport.close(); //关闭连接

}

public static void request(Account.Client client, Request req) throws TException{
try {
String result = client.doAction(req);
System.out.println(result);
} catch (InvalidOperation e) {
System.out.println(e.reason);
}
}
}

运行客户端,其结果如下所示。

Login failed!! please check your username and password
Register success!! Hello wuchong
Login success!! Hello wuchong
param name should not be empty

而此时,服务端会打印出收到的请求信息。

Starting the Account server...
Get request[name:wuchong, pass:1234, op:1]
Get request[name:wuchong, pass:1234, op:2]
Get request[name:wuchong, pass:1234, op:1]
Get request[name:, pass:1234, op:1]

你可以发现,只需要几行代码,我们就实现了高效的RPC通信。

##参考资料


hoxis wechat