gRPC从0到1系列【22】
文章目录
- gRPC拦截器
- 7.3.4 注册Interceptor
- 7.3.5 底层原理分析
- 7.3.6 最佳实践与注意事项
- 7.3.7 总结
gRPC拦截器
7.3.4 注册Interceptor
✅ 1. 单个Interceptor注册
Server server = ServerBuilder.forPort(8080).addService(new GreeterServiceImpl()).intercept(new LoggingServerInterceptor()) // 添加拦截器.build();
✅ 2. 多个 Interceptor(链式)
Server server = ServerBuilder.forPort(8080).addService(new GreeterServiceImpl()).intercept(new AuthServerInterceptor()) // 先执行.intercept(new LoggingServerInterceptor()) // 后执行.intercept(new UserContextInterceptor()) // 最后执行(最靠近业务).build();
🔁 执行顺序:
- 请求阶段:从
addService
后第一个intercept()
开始,依次执行。- 响应阶段:逆序执行(类似栈)
7.3.5 底层原理分析
✅ 1. 调用链构建
gRPC 内部将多个 ServerInterceptor 和 BindableService 组合成一个责任链:
ServerCallHandler finalHandler = (call, headers) -> {return serviceImpl.bindService().apply(call, headers);
};for (ServerInterceptor interceptor : interceptors) {finalHandler = (call, headers) -> interceptor.interceptCall(call, headers, finalHandler);
}
最终调用时,形成嵌套结构:
Interceptor1.interceptCall(call,headers,(call, headers) -> Interceptor2.interceptCall(call,headers,(call, headers) -> ServiceImpl...)
)
✅ 2. 为什么能控制请求/响应
- 请求控制:通过返回自定义
ServerCall.Listener
,重写onMessage()
、onHalfClose()
等方法。 - 响应控制:通过包装
ServerCall
,重写sendMessage()
、close()
方法。
7.3.6 最佳实践与注意事项
✅ 最佳实践
- 轻量级:Interceptor 应快速执行,避免阻塞 I/O。
- 异常安全:捕获异常,避免导致整个服务崩溃。
- 资源清理:在
close()
中释放资源(如 MDC 清理)。 - 顺序合理:认证 → 日志 → 业务上下文。
- 使用 Context:传递请求级数据,避免 ThreadLocal。
⚠️ 常见错误
错误 | 后果 | 修复 |
---|---|---|
忘记调用 super.close() | 客户端 hang 住 | 必须调用父类方法 |
在 interceptCall 中抛异常 | 服务崩溃 | 捕获异常并返回 Status.INTERNAL |
修改不可变 Metadata | 运行时异常 | 使用 new Metadata() 并 copy |
7.3.7 总结
特性 | 说明 |
---|---|
功能强大 | 支持请求/响应拦截、元数据操作、上下文注入 |
非侵入式 | 业务代码零修改 |
链式组合 | 多个拦截器可灵活组合 |
性能高效 | 基于回调,无反射开销 |
适用场景 | 认证、日志、监控、限流、调试、多租户等 |
ServerInterceptor 是 gRPC 服务端开发的基石组件,掌握它能极大提升系统可观测性与安全性。建议在所有生产级 gRPC 服务中合理使用拦截器。
🔚 提示:客户端也有 ClientInterceptor,机制类似,可用于统一设置请求头、重试等。