gRPC从0到1系列【20】

文章目录

  • 七、gRPC拦截器
    • [7.1 拦截器概述](#7.1 拦截器概述)
      • [7.1.1 什么是gRPC拦截器?](#7.1.1 什么是gRPC拦截器?)
      • [7.1.2 拦截器的类型划分](#7.1.2 拦截器的类型划分)
      • [7.1.3 核心接口](#7.1.3 核心接口)
      • [7.1.4 调用链](#7.1.4 调用链)
      • [7.1.5 流程图](#7.1.5 流程图)
    • [7.2 工作原理与生命周期](#7.2 工作原理与生命周期)
      • [7.2.1 拦截器处理流程](#7.2.1 拦截器处理流程)
      • [7.2.2 拦截器的执行顺序](#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 核心接口

java 复制代码
// 服务端拦截器
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 调用链

bash 复制代码
客户端: 
[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) 的拦截流程 (以服务端为例):
Client InterceptorChain LoggingInterceptor AuthInterceptor BusinessLogic 1. Send RPC Request 2. Invoke interceptor 3. Check credentials in Metadata 4. Proceed to next interceptor 5. Log request details 6. Proceed to business logic 7. Execute business code 8. Return response 9. Log response details 10. Return response 11. Return response 12. Send RPC Response 4. Return error (UNAUTHENTICATED) 5. Send RPC Error alt [Valid] [Invalid] Client InterceptorChain LoggingInterceptor AuthInterceptor BusinessLogic

核心方法:

  • Context: 每个 RPC 调用都关联一个 Context对象,它像一个 "上下文" 或 "环境",可以在拦截器链和业务逻辑之间传递数据(如用户身份信息)。它是不可变的,但可以通过 withValue() 创建一个包含新值的子上下文。
  • next 在拦截器的实现中,ServerCallHandler (服务端) 或 ClientCall (客户端) 对象通常被命名为 next。调用 next.startCall()或 next.invoke()意味着将 RPC 调用传递给链中的下一个拦截器 。如果当前拦截器是最后一个,则 next 指向实际的业务逻辑实现。如果不调用 next,整个调用链将被中断。

7.2.2 拦截器的执行顺序

java 复制代码
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. 响应拦截器 (逆向顺序)");
    }
}
  • 客户端拦截器执行顺序: 添加顺序 → 实际调用 → 响应顺序
  • 服务器拦截器执行顺序: 添加顺序 → 实际处理 → 响应顺序
相关推荐
无敌最俊朗@3 小时前
STL-vector面试剖析(面试复习4)
java·面试·职场和发展
PPPPickup3 小时前
easychat项目复盘---获取联系人列表,联系人详细,删除拉黑联系人
java·前端·javascript
LiamTuc3 小时前
Java构造函数
java·开发语言
长安er3 小时前
LeetCode 206/92/25 链表翻转问题-“盒子-标签-纸条模型”
java·数据结构·算法·leetcode·链表·链表翻转
菜鸟plus+3 小时前
N+1查询
java·服务器·数据库
我要添砖java4 小时前
《JAVAEE》网络编程-什么是网络?
java·网络·java-ee
CoderYanger4 小时前
动态规划算法-01背包问题:50.分割等和子集
java·算法·leetcode·动态规划·1024程序员节
菜鸟233号5 小时前
力扣513 找树左下角的值 java实现
java·数据结构·算法·leetcode
Neoest6 小时前
【EasyExcel 填坑日记】“Syntax error on token )“: 一次编译错误在逃 Runtime 的灵异事件
java·eclipse·编辑器
自在极意功。6 小时前
Web开发中的分层解耦
java·microsoft·web开发·解耦