前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >gRPC-Java 的快速实践

gRPC-Java 的快速实践

原创
作者头像
花花Binki
发布2025-01-03 22:58:57
发布2025-01-03 22:58:57
840
举报
文章被收录于专栏:岚的工作随笔岚的工作随笔

在 Java 的单体应用中,想要进行不同层级间的调用通常使用Spring的依赖注入。而到了分布式系统中,服务上下文变成了通信上下文,每一次调用变成了网络请求。这对于业务开发来说,会浪费一定时间来考虑这些冗余代码。

这时,聪明的你想到了AOP,做统一拦截,再发送。对于发送内容,转换为统一的 JSON。那么恭喜,你已经开发了一款简易的RPC(Remote Procedure Call)框架!

简介

将 RPC 比作普通话,那么gRPC就是谷歌的方言。gRPC 是由 Google 开发并且开源的一款高性能、跨语言的 RPC 框架,支持多种语言,Java 就包含其中。

所以你可以通过框架调用 C 或 go 的服务,像调用本地库一样。

调用图例
调用图例

官方入门解读

准备工作

官方教程中,需求 JDK > 7。但对于部分Gradle版本来说,可能需要 11 以上。

克隆仓库

代码语言:shell
复制
git clone -b v1.69.0 --depth 1 https://github.com/grpc/grpc-java

这里克隆的是全量包,我们只需要example目录下的

代码语言:shell
复制
cd examples
# 编译,可能会下载Gradle。准备好网络环境
./gradlew installDist

见到如下字样即成功

编译成功
编译成功

接下来需要准备两个终端,分别运行服务端与客户端

服务端:

代码语言:shell
复制
./build/install/examples/bin/hello-world-server
服务端信息
服务端信息

客户端:

代码语言:shell
复制
./build/install/examples/bin/hello-world-client
客户端信息
客户端信息

注:客户端启动后,得到结果后,便会立即退出。

代码细节

上述两个运行的是bat文件,根据路径可以查看启动来源

hello-world-server.bat 77行

代码语言:shell
复制
@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、端口参数可选:

代码语言:java
复制
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);
    }
  }

实现原理

gRPC 原理极简图解
gRPC 原理极简图解

大都是些耳熟能详的技术,下面挑序列化展开介绍。

Protobuf

在进行网络数据传输中,信息都是以二进制格式保存的。所以为了能让对方可以正确解析出对象,应该制定一些通用规则。JSON 是第一个可以想到的,但对于一些场景来说,还是有点慢。所以对 JSON 进行再压缩,双端保持“解压密匙”,这样信息相同,包更小的情况下,效率就更快了。Protobuf 就是这样一个序列化格式神器,相比于 JSON 而言,普遍快了 4 倍以上。

回到代码中,src/main/proto/grpc/helloworld.proto

代码语言:txt
复制
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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 官方入门解读
    • 准备工作
    • 代码细节
    • 实现原理
      • Protobuf
  • 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档