gRPC从0到1系列【20】
文章目录
- 七、gRPC拦截器
- 7.1 拦截器概述
- 7.1.1 什么是gRPC拦截器?
- 7.1.2 拦截器的类型划分
- 7.1.3 核心接口
- 7.1.4 调用链
- 7.1.5 流程图
- 7.2 工作原理与生命周期
- 7.2.1 拦截器处理流程
- 7.2.2 拦截器的执行顺序
七、gRPC拦截器
7.1 拦截器概述
7.1.1 什么是gRPC拦截器?
gRPC 拦截器是一种AOP (面向切面编程) 的实现,允许你在 RPC 调用的生命周期的特定节点(如调用前、调用后、出错时)注入自定义逻辑,而无需修改 RPC 方法本身的业务代码。
你可以把拦截器想象成 RPC 调用的 “安检员” 或 “门卫”:
- 在调用到达业务逻辑之前:检查调用者的身份(认证)、记录请求日志、修改或添加元数据。
- 在业务逻辑执行之后:记录响应日志、收集性能指标(如耗时)、修改或添加响应的元数据。
- 在发生异常时:记录错误日志、将业务异常转换为标准的 gRPC
Status
错误。
拦截器的核心价值在于解耦:将与业务无关的通用功能(如日志、监控、安全)从业务代码中分离出来,实现代码的模块化和复用。
7.1.2 拦截器的类型划分
gRPC 拦截器分为 客户端 和 服务端 两大类,每类又根据 RPC 模式细分:
✅ 1. 服务器端拦截器【ServerInterceptor】
RPC 类型 | 拦截器方法签名(Java) |
---|---|
Unary(一元) | UnaryServerInterceptor |
Server Streaming | ServerStreamingServerInterceptor |
Client Streaming | ClientStreamingServerInterceptor |
Bidirectional Streaming | BidiStreamingServerInterceptor |
✅ 通用做法:使用
ServerInterceptor
接口(底层自动适配所有类型)
✅ 2. 客户端拦截器【ClientInterceptor】
RPC 类型 | 拦截器方法签名(Java) |
---|---|
Unary | UnaryClientInterceptor |
Streaming(三种流) | StreamingClientInterceptor |
✅ 通用做法:使用
ClientInterceptor
接口
7.1.3 核心接口
// 服务端拦截器
public interface ServerInterceptor {<ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,Metadata headers,ServerCallHandler<ReqT, RespT> next);
}// 客户端拦截器
public interface ClientInterceptor {<ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,CallOptions callOptions,Channel next);
}
7.1.4 调用链
客户端:
[App] → [Interceptor1] → [Interceptor2] → ... → [Network]服务端:
[Network] → [Interceptor1] → [Interceptor2] → ... → [Business Logic]
next
参数:代表“下一个拦截器或最终处理者”- 必须调用
next.xxx()
,否则调用链中断!
7.1.5 流程图
7.2 工作原理与生命周期
7.2.1 拦截器处理流程
拦截器的工作基于责任链模式 (Chain of Responsibility)。你可以为一个 gRPC 通道(Channel)或服务注册多个拦截器,它们会按特定顺序形成一个 “拦截器链”。
一元 RPC (Unary RPC) 的拦截流程 (以服务端为例):
核心方法:
- Context: 每个 RPC 调用都关联一个 Context对象,它像一个 “上下文” 或 “环境”,可以在拦截器链和业务逻辑之间传递数据(如用户身份信息)。它是不可变的,但可以通过
withValue()
创建一个包含新值的子上下文。- next 在拦截器的实现中,ServerCallHandler (服务端) 或
ClientCall
(客户端) 对象通常被命名为next
。调用 next.startCall()或 next.invoke()意味着将 RPC 调用传递给链中的下一个拦截器。如果当前拦截器是最后一个,则next
指向实际的业务逻辑实现。如果不调用next
,整个调用链将被中断。
7.2.2 拦截器的执行顺序
package com.example.grpc.interceptor;import io.grpc.*;/*** gRPC 拦截器核心概念演示*/
public class InterceptorConcepts {/*** 拦截器执行顺序示意图* * 客户端拦截器执行顺序: 添加顺序 → 实际调用 → 响应顺序* 服务器拦截器执行顺序: 添加顺序 → 实际处理 → 响应顺序*/// 客户端调用流程public static void demonstrateClientFlow() {System.out.println("=== 客户端拦截器执行顺序 ===");System.out.println("1. 请求拦截器 (正向顺序)");System.out.println("2. 实际RPC调用");System.out.println("3. 响应拦截器 (逆向顺序)");}// 服务器调用流程 public static void demonstrateServerFlow() {System.out.println("=== 服务器拦截器执行顺序 ===");System.out.println("1. 请求拦截器 (正向顺序)");System.out.println("2. 实际服务处理");System.out.println("3. 响应拦截器 (逆向顺序)");}
}
- 客户端拦截器执行顺序: 添加顺序 → 实际调用 → 响应顺序
- 服务器拦截器执行顺序: 添加顺序 → 实际处理 → 响应顺序