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

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
腾讯CDC
V
V2EX
Martin Fowler
Martin Fowler
A
About on SuperTechFans
大猫的无限游戏
大猫的无限游戏
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Check Point Blog
博客园 - 【当耐特】
Cisco Talos Blog
Cisco Talos Blog
The Hacker News
The Hacker News
K
Kaspersky official blog
Security Latest
Security Latest
H
Help Net Security
博客园_首页
美团技术团队
Spread Privacy
Spread Privacy
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
G
Google Developers Blog
NISL@THU
NISL@THU
爱范儿
爱范儿
I
Intezer
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
N
News and Events Feed by Topic
P
Privacy International News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Security @ Cisco Blogs
Schneier on Security
Schneier on Security
雷峰网
雷峰网
人人都是产品经理
人人都是产品经理
V
Vulnerabilities – Threatpost
W
WeLiveSecurity
P
Palo Alto Networks Blog
G
GRAHAM CLULEY
Hacker News: Ask HN
Hacker News: Ask HN
I
InfoQ
The Cloudflare Blog
F
Full Disclosure
SecWiki News
SecWiki News
宝玉的分享
宝玉的分享
N
Netflix TechBlog - Medium

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 原理与实现:架构和拓扑概览 Flink 原理与实现:内存管理 Flink 原理与实现:如何处理反压问题 Flink官方文档翻译:安装部署(集群模式) Flink官方文档翻译:安装部署(本地模式) 迟到的2015年终总结 高效Macbook开发之道(工具篇) Clojure学习笔记(三):并发与引用 Clojure学习笔记(二):语法 Clojure学习笔记(一):数据结构 Thrift 入门 Metrics 是个什么鬼 之入门教程 使用Redis和SQLAlchemy对Scrapy Item去重并存储 使用Scrapy定制可动态配置的爬虫 编程方式下运行 Scrapy spider 读《程序员必读的职业规划书》 Spark 下操作 HBase(1.0.0 新 API) HBase 集群安装部署 Spark On YARN 集群安装部署 Git 常用技能
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