文章目录
- 一、Stub核心
-
- [1.1 干什么是Stub?](#1.1 干什么是Stub?)
- [1.2 Stub的类型(四种调用模式)](#1.2 Stub的类型(四种调用模式))
- [1.3 Stub的核心定位(远程服务器的本地代理)](#1.3 Stub的核心定位(远程服务器的本地代理))
- [1.4 Stub的主要类型与适用场景](#1.4 Stub的主要类型与适用场景)
-
- [1.4.1 阻塞式 Stub (Blocking Stub / Synchronous Stub)](#1.4.1 阻塞式 Stub (Blocking Stub / Synchronous Stub))
- [1.4.2 异步 Stub (Asynchronous Stub / Non-blocking Stub)](#1.4.2 异步 Stub (Asynchronous Stub / Non-blocking Stub))
- [1.4.3 流式 Stub (Streaming Stub)](#1.4.3 流式 Stub (Streaming Stub))
- [1.5 Stub工作原理与生命周期](#1.5 Stub工作原理与生命周期)
一、Stub核心
gRPC 的 Stub(存根) 是客户端与服务端之间通信的关键桥梁。它隐藏了底层网络调用、序列化、协议细节,使开发者能像调用本地函数一样调用远程服务。
1.1 干什么是Stub?
Stub(存根) 是 gRPC 客户端侧的代理对象,封装了对远程 gRPC 服务的调用逻辑。它由 Protocol Buffers 编译器(protoc
)配合 gRPC 插件自动生成,提供强类型、面向接口的 API。
✅ 核心作用:将"远程过程调用"伪装成"本地函数调用"。
客户端代码 Stub代理 序列化/反序列化 网络传输层 gRPC服务器 实际服务实现 隐藏网络细节 方法映射 错误处理
类比理解一下:
- 传统 RPC:你需要手动构造请求、建立连接、发送字节、解析响应。
- gRPC Stub :你只需调用
client.SayHello(req)
,其余一切由 Stub 自动完成。
1.2 Stub的类型(四种调用模式)
gRPC 支持四种服务方法类型,对应四种 Stub 行为:
类型 | 描述 | Stub 行为 |
---|---|---|
Unary RPC | 一请求一响应 | 同步/异步函数调用 |
Server Streaming | 一请求多响应 | 返回流对象,循环读取 |
Client Streaming | 多请求一响应 | 发送多个请求后获取响应 |
Bidirectional Streaming | 多请求多响应 | 双向流,可并发读写 |
Stub UnaryStub ServerStreamingStub ClientStreamingStub BidiStreamingStub
1.3 Stub的核心定位(远程服务器的本地代理)
在分布式系统中,客户端需要调用远程服务器上的方法。直接处理网络通信(如建立连接、发送数据、处理响应)是非常复杂且容易出错的。
gRPC Stub (客户端) 正是为了解决这个问题而存在的。它扮演了一个 "远程服务的本地代理" 角色。
- 对客户端应用来说:调用 Stub 的方法就像调用一个本地对象的方法一样简单、直观,完全感觉不到网络的存在。
- 对 gRPC 框架来说:Stub 负责将客户端的本地调用 "翻译" 成符合 gRPC 协议的网络请求,并将从网络接收到的响应 "翻译" 回客户端可以理解的返回值。
一句话总结:Stub 屏蔽了所有底层的网络通信细节,让远程调用像本地调用一样简单。

1.4 Stub的主要类型与适用场景
根据不同的通信模式,gRPC 提供了多种类型的 Stub。
1.4.1 阻塞式 Stub (Blocking Stub / Synchronous Stub)
- 特点 :客户端调用方法后,当前线程会阻塞,直到收到服务端的响应或发生错误。
- 适用场景
- 简单的请求 - 响应模式。
- 业务逻辑简单,对响应时间不敏感,或者可以容忍线程阻塞的场景。
- 适合快速开发和调试。
- 示例:HelloServiceGrpc.newBlockingStub(channel)
1.4.2 异步 Stub (Asynchronous Stub / Non-blocking Stub)
-
特点 :客户端调用方法后,线程立即返回 ,不会等待响应。结果通过回调函数 (Callback) 或 Future/Promise 对象来获取。
-
适用场景
- 需要高并发处理大量请求的场景。
- 不希望阻塞主线程(如 UI 线程、事件循环线程)的应用。
- 构建高性能、响应式的系统。
-
示例:HelloServiceGrpc.newFutureStub(channel) (Java) 或 HelloServiceGrpc.newStub(channel) (Java StreamObserver 模式)
1.4.3 流式 Stub (Streaming Stub)
流式 Stub 是基于异步 Stub 实现的,用于处理流式 RPC。
- 客户端流式 Stub:客户端可以连续发送多个请求消息,服务端在接收完所有消息后返回一个响应。
- 服务端流式 Stub:客户端发送一个请求,服务端可以连续返回多个响应消息。
- 双向流式 Stub:客户端和服务端可以像打电话一样,互相独立地发送一个消息流。
1.5 Stub工作原理与生命周期
✅ 工作原理(以一次 Unary RPC 为例)
- 创建 Call 对象 :当客户端调用 Stub 的某个方法时(如
stub.sayHello(req)
),Stub 会首先创建一个Call
对象。Call
代表了一次完整的 RPC 调用。 - 封装请求 :Stub 将传入的请求参数(
req
)使用 Protobuf 进行序列化,打包成 HTTP/2 的数据帧(Data Frame)。 - 设置元数据 :Stub 将
Context
中携带的元数据(Metadata,如认证 Token、自定义 Header)也封装成 HTTP/2 的头帧(Header Frame)。 - 发送请求 :Stub 将这些帧通过
Channel
发送给服务端。Channel
负责管理底层的 TCP 连接和 HTTP/2 会话。 - 等待响应
- 对于阻塞式 Stub ,调用线程会进入等待状态,直到
Channel
接收到服务端的响应帧。 - 对于异步 Stub,调用线程立即返回,gRPC 框架会在后台监听响应。当响应到达时,通过回调或完成 Future 来通知应用。
- 对于阻塞式 Stub ,调用线程会进入等待状态,直到
- 解析响应 :
Channel
接收到响应帧后,将其传递给 Stub。Stub 使用 Protobuf 将二进制数据反序列化成响应对象。 - 返回结果:Stub 将最终的响应对象返回给客户端应用。
✅ 生命周期
- 创建 :
Stub
实例通过 XXXGrpc.newXXXStub(channel)方法创建。创建时需要传入一个Channel
对象,Stub
的生命周期与它所绑定的Channel
紧密相关。 - 复用 :
Stub
是无状态 的,因此可以被安全地复用 。创建Stub
的开销很小,但创建Channel
的开销较大。最佳实践是:创建一个共享的Channel
,并基于它创建多个Stub
,在整个应用程序生命周期中复用它们。 - 销毁 :
Stub
本身没有需要手动释放的资源。当不再需要时,直接丢弃引用即可,由垃圾回收器(GC)处理。真正需要管理的是Channel
,必须在应用退出时调用channel.shutdown()
或channel.close()
来释放网络连接等资源。