在 Java 的单体应用中,想要进行不同层级间的调用通常使用Spring的依赖注入。而到了分布式系统中,服务上下文变成了通信上下文,每一次调用变成了网络请求。这对于业务开发来说,会浪费一定时间来考虑这些冗余代码。
这时,聪明的你想到了AOP,做统一拦截,再发送。对于发送内容,转换为统一的 JSON。那么恭喜,你已经开发了一款简易的RPC(Remote Procedure Call)框架!
将 RPC 比作普通话,那么gRPC就是谷歌的方言。gRPC 是由 Google 开发并且开源的一款高性能、跨语言的 RPC 框架,支持多种语言,Java 就包含其中。
所以你可以通过框架调用 C 或 go 的服务,像调用本地库一样。
官方教程中,需求 JDK > 7。但对于部分Gradle版本来说,可能需要 11 以上。
克隆仓库
git clone -b v1.69.0 --depth 1 https://github.com/grpc/grpc-java
这里克隆的是全量包,我们只需要example目录下的
cd examples
# 编译,可能会下载Gradle。准备好网络环境
./gradlew installDist
见到如下字样即成功
接下来需要准备两个终端,分别运行服务端与客户端
服务端:
./build/install/examples/bin/hello-world-server
客户端:
./build/install/examples/bin/hello-world-client
注:客户端启动后,得到结果后,便会立即退出。
上述两个运行的是bat文件,根据路径可以查看启动来源
hello-world-server.bat 77行
@rem Execute hello-world-server
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %HELLO_WORLD_SERVER_OPTS% -classpath "%CLASSPATH%" io.grpc.examples.helloworld.HelloWorldServer %*
@rem
是一个批处理命令,用于添加注释,不会被执行。
"%JAVA_EXE%"
是一个环境变量,指向 Java 运行时环境(JRE)的可执行文件路径。
%DEFAULT_JVM_OPTS%
是一个环境变量,包含默认的 Java 虚拟机(JVM)选项。
%JAVA_OPTS%
是一个环境变量,包含传递给 Java 应用程序的额外选项。
%HELLO_WORLD_SERVER_OPTS%
是一个环境变量,包含特定于HelloWorldServer
的选项。
-classpath "%CLASSPATH%"
指定了类路径,告诉 Java 运行时在哪里查找类文件。
io.grpc.examples.helloworld.HelloWorldServer
是要执行的 Java 类的完全限定名。
%*
表示传递给批处理脚本的所有参数。
根据信息,找到 src/main/java/io/grpc/examples/helloworld/HelloWorldServer
而在客户端上,逻辑更为简单。只是多留了一个IP、端口参数可选:
public static void main(String[] args) throws Exception {
// 省略参数处理逻辑
// 创建一个到gRPC服务器的连接通道
ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create())
.build();
try {
// 初始化
HelloWorldClient client = new HelloWorldClient(channel);
// 请求
client.greet(user);
} finally {
// 5秒后关闭channel
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}
}
大都是些耳熟能详的技术,下面挑序列化展开介绍。
在进行网络数据传输中,信息都是以二进制格式保存的。所以为了能让对方可以正确解析出对象,应该制定一些通用规则。JSON 是第一个可以想到的,但对于一些场景来说,还是有点慢。所以对 JSON 进行再压缩,双端保持“解压密匙”,这样信息相同,包更小的情况下,效率就更快了。Protobuf 就是这样一个序列化格式神器,相比于 JSON 而言,普遍快了 4 倍以上。
回到代码中,src/main/proto/grpc/helloworld.proto
syntax = "proto3"; // 指定使用proto3语法
option java_multiple_files = true; // 生成多个Java文件
option java_package = "io.grpc.examples.helloworld"; // 设置生成的Java文件的包名
option java_outer_classname = "HelloWorldProto"; // 设置生成的Java文件的外部类名
option objc_class_prefix = "HLW"; // 设置Objective-C类的前缀
package helloworld; // 定义包名
// 定义greeting服务
service Greeter {
// 定义一个RPC方法,接收HelloRequest消息,返回HelloReply消息
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// 定义请求消息,包含用户的名字
message HelloRequest {
string name = 1; // 字段编号为1的字符串类型字段,表示用户名。可以继续按序号添加字段。
}
// 定义响应消息,包含问候语
message HelloReply {
string message = 1; // 字段编号为1的字符串类型字段,表示问候语
}
这是一个特殊的消息结构,*.proto就是双端的密匙。定义好结构后,还需要
Protobuf编译器protoc将该文件编译为目标语言的代码,用于序列化和反序列化。
示例中的代码输出示例
请不要修改这里的代码,包括格式化!
以上,就是gRPC的一个快速入门示例解读,希望对你有所帮助!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。