资讯动态

手写 API 网关第4章:将 RPC、HTTP 等连接抽象为数据源,打造可扩展的网关通信底座

发布时间:2026/9/23 14:18:13 来源:尧图企业网站定制
文档教程后端【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址https://gitcode.com/gh_mirrors/code/CodeGuide点击查看免费下载本文是《API网关》手写系列的第 4 章解读。围绕将连接RPC、HTTP、其他抽象为数据源这一核心设计结合仓库内配套章节文档与源码级实现讲清楚为什么网关要把 RPC 连接当作数据源来管理、如何像 ORM 框架一样池化与扩展连接资源以及这一抽象为后续 HTTP 参数解析、执行器封装、SPI 自定义扩展预留了哪些能力。读完你不仅能复现这套抽象模型还能理解大型网关中会话、数据源、执行器三者解耦的设计思路。一、本章在网关项目中的位置与学习指引在整个 API 网关的演进路线上本章属于第 1 部分 - 通信组件中的关键一环前后章节的关系如下第1章HTTP请求会话协议处理用 Netty 接收 HTTP 请求构建网关会话服务第2章代理RPC泛化调用把网关 HTTP 接口与 RPC 服务建立绑定封装泛化调用第3章分治处理会话流程拆分会话业务逻辑与网络通信拆分 bind 包下代理与 RPC 泛化调用第4章本章把 RPC、HTTP 等连接抽象为数据源为后续数据源 执行器的调用模型打下基础第5章HTTP请求参数解析 与 第6章引入执行器封装服务调用 则在此抽象之上继续细化参数处理与调用封装。本章难度★★★☆☆本章重点拆解 Dubbo、HTTP 调用抽象为数据源服务便于后续功能的扩展和使用。1. 为什么先做能用的核心案例再做职责拆解你可能会发现作者一贯的开发套路在功能实现上先开发一个只要能满足功能的核心逻辑案例之后对案例中代码的职责进行拆解细分也就是使用框架结构、设计原则和设计模式等手段将不同的功能模块分区实现构建出界限上下文。从前期来看这样的实现过程要比仅使用一个类if···else开发的代码交付速度慢了不少。那么从架构设计和开发上为什么这么干因为长期来看代码的成本远不是最开始的开发阶段而是在后期的维护、迭代、扩展、满足产品新增差异化需求时所投入的研发资源。所以对于有稳定长发展周期的项目来说这样做是值得的。本章要做的就是把 API 网关中关于 RPC 的泛化调用使用提炼出来把它抽象为一种数据连接资源进行使用。这样也就方便在这个框架中扩展其他的连接资源包括各个厂家的 RPC 实现、HTTP 服务、WebService 调用等并还可以通过 SPI 的方式进行自定义连接资源扩展以适应不同场景的诉求。二、抽象连接把 RPC 当作数据源来维护API 网关的实现对 RPC 接口的泛化调用类似于 ORM 框架中对数据库的调用。既然 MyBatis 可以把数据库抽象为数据源DataSource统一管理连接、支持池化那么网关同样可以把 RPC 抽象成一种连接资源做数据源的管理和池化的实现。这样设计的目的非常明确方便扩展新的连接方式各类厂商的 RPC 框架、HTTP 服务、你提供的大数据原始接口服务都可以被这样包装处理统一的管理模型把连接从具体的调用细节中解放出来网关核心流程只面向抽象的数据源编程而不关心背后是 Dubbo 还是 HTTP池化与复用像数据库连接池一样对连接资源做管理为高并发下的连接复用与性能优化预留空间。1. 网关通信模型中的位置到本章为止整个 API 网关的通信模型结构已经逐步清晰网络协议转换 - 开启通信会话 - 获取映射关系 - 执行具体的请求方案 - 抽象的数据源一次 HTTP 请求进入网关经过 Netty 的协议转换后开启一次网关会话会话根据请求 URI 获取到 HTTP 与 RPC 的映射关系绑定执行具体的请求方案泛化调用等而被调用的目标被统一抽象为数据源把 RPC、HTTP 当做数据源来维护。在这一系列内容的开发中你会慢慢体会到职责的分离、功能模块的解耦以及为扩展预留出了哪些东西。这也正是本章最值得学习的地方不是怎么写泛化调用而是怎么把泛化调用设计成可扩展的抽象。三、从会话模型看数据源抽象的实现为了印证本章的设计思路我们可以从仓库中 《API 网关 - 媲美美团这套Shepherd网关架构》 一文展示的会话模型源码看到这套数据源抽象最终落地后的样子。1. DefaultGatewaySessionFactory会话与数据源的衔接源码类cn.bugstack.gateway.core.session.defaults.DefaultGatewaySessionFactorypublic class DefaultGatewaySessionFactory implements GatewaySessionFactory { private final Configuration configuration; public DefaultGatewaySessionFactory(Configuration configuration) { this.configuration configuration; } Override public GatewaySession openSession(String uri) { // 获取数据源连接信息这里把 Dubbo、HTTP 抽象为一种连接资源 DataSourceFactory dataSourceFactory new UnpooledDataSourceFactory(); dataSourceFactory.setProperties(configuration, uri); DataSource dataSource dataSourceFactory.getDataSource(); // 创建执行器 Executor executor configuration.newExecutor(dataSource.getConnection()); // 创建会话DefaultGatewaySession return new DefaultGatewaySession(configuration, uri, executor); } public Configuration getConfiguration() { return configuration; } }从这段代码可以清晰看到本章抽象连接为数据源的最终形态DataSourceFactory根据 URI 获取对应的数据源工厂UnpooledDataSourceFactory是无池化的数据源工厂实现注释中明确这里把 Dubbo、HTTP 抽象为一种连接资源DataSource数据源是网关调用后端服务的统一入口抽象Executor执行器由配置中心创建封装对数据源的调用DefaultGatewaySession会话把请求上下文与执行器串起来向外部屏蔽了底层连接细节。也就是说会话模型是网关算力中非常重要的一环所有的 HTTP 请求都可以被抽象为会话模型。通过会话模型封装出 HTTP 到 RPC 的处理中间再通过执行器和 RPC 抽象的数据源进行衔接。这套结构与 MyBatis 的SqlSessionFactory - SqlSession - Executor - DataSource模型高度同构一个对数据库处理一个对 RPC 服务处理。所有学习都是举一反三核心的设计万变不离其宗。2. MapperProxyFactory泛化调用与数据源绑定数据源抽象之后网关仍然需要HTTP 地址 - RPC 服务的绑定关系。仓库同文中展示的cn.bugstack.gateway.core.bind.MapperProxyFactory给出了答案public class MapperProxyFactory { private String uri; public MapperProxyFactory(String uri) { this.uri uri; } private final MapString, IGenericReference genericReferenceCache new ConcurrentHashMap(); public IGenericReference newInstance(GatewaySession gatewaySession) { return genericReferenceCache.computeIfAbsent(uri, k - { HttpStatement httpStatement gatewaySession.getConfiguration().getHttpStatement(uri); // 泛化调用 MapperProxy genericReferenceProxy new MapperProxy(gatewaySession, uri); // 创建接口 InterfaceMaker interfaceMaker new InterfaceMaker(); interfaceMaker.add(new Signature(httpStatement.getMethodName(), Type.getType(String.class), new Type[]{Type.getType(String.class)}), null); Class? interfaceClass interfaceMaker.create(); // 代理对象 Enhancer enhancer new Enhancer(); enhancer.setSuperclass(Object.class); // IGenericReference 统一泛化调用接口 // interfaceClass 根据泛化调用注册信息创建的接口建立 http - rpc 关联 enhancer.setInterfaces(new Class[]{IGenericReference.class, interfaceClass}); enhancer.setCallback(genericReferenceProxy); return (IGenericReference) enhancer.create(); }); } }结合 第2章代理RPC泛化调用 的内容这里的关键点有三泛化调用RPC 接口设计中提供的一种反射调用机制你不需要硬编码调用接口只需要提供接口的方法名称、入参信息即可调用到对应的 RPC 接口服务代理包装虽然 RPC 框架提供了泛化调用但直接使用存在硬编码风险、不利于迭代升级也不方便扩展其他接口——因为每一个 RPC 实现的泛化调用方法名称有所不同扩展非 RPC 框架的逻辑也不方便处理所以需要单独提供一层代理包装逻辑Cglib 代理IGenericReference是统一泛化调用接口interfaceClass是根据泛化调用注册信息HttpStatement中的方法名与入参签名通过InterfaceMaker动态创建出的接口二者同时作为 CglibEnhancer的接口集合最终生成既满足统一调用约定、又具备 HTTP→RPC 关联语义的代理对象。genericReferenceCache则按 URI 做缓存复用避免重复创建代理。3. 会话与执行器的职责划分本章抽象出数据源后后续章节进一步明确了分工。在 第6章引入执行器封装服务调用 中有一句非常精辟的总结会话的职责是负责串联上下文执行器的职责是负责对数据源的调用信息处理。会话流程中原本冗余的对数据源RPC调用时入参、出参的封装被提取到专门的 executor 执行器类中统一管理执行器封装对数据源RPC的调用以及处理相关的入参、出参信息并把网关调用结果封装到标准的结果类包含 code 码、info 描述、data 结果信息会话只负责流程串联让整个代码调用能看到主要干路清晰化流程方便后续维护。这一章第6章之所以能顺利拆出执行器正是因为第 4 章先把连接抽象成了统一的数据源先有统一的连接抽象才有统一的执行器封装。四、为什么说这是为了扩展的设计回顾 第3章分治处理会话流程 的重构点其中有一条是拆分 bind 包下代理和对 RPC 接口的泛化调用这里你可以把 RPC 当做一种可连接资源而这种连接资源也不是只有 RPC 一种同时也因为 RPC 的泛化调用是一种通用方法并不需要与逻辑绑定所以它也应该被拆分出来。结合本章的抽象数据源整套扩展思路可以归纳为扩展维度抽象落点说明连接类型DataSource/DataSourceFactory将各类厂商的 RPC 框架、HTTP 服务、WebService、大数据原始接口统一为数据源连接来源SPI 机制通过 SPI 方式进行自定义连接资源扩展适应不同场景诉求调用封装Executor执行器统一处理数据源的入参、出参与结果封装会话不再关心底层调用细节绑定关系MapperProxyFactoryIGenericReferenceHTTP 地址与后端服务建立映射代理对象统一承载泛化调用其中池化是一个重要方向原文档明确提到做数据源的管理和池化的实现即像数据库连接池一样对连接资源做复用管理。这在网关承接高并发流量时是提升性能、降低重复建连开销的关键设计仓库中UnpooledDataSourceFactory即为无池化实现为后续引入池化版本预留了工厂接口。1. 这套抽象在整套网关架构中的意义从仓库的 《API网关》开篇 与 API网关架构设计 可以看到整套网关被拆分为网关核心系统api-gateway-core、网关管理系统api-gateway-admin、网关注册组件api-gateway-sdk、网关注册中心api-gateway-center、网关测试工程provider / consumer等微服务工程。而抽象数据源正是网关核心系统api-gateway-core通信链路中最底层的支撑对外网关算力接收 HTTP 请求进行协议转换后泛化调用 RPC 服务返回数据对内所有被调用的后端资源统一走数据源抽象会话、执行器、绑定代理各司其职。这也正是面试中可以把将连接RPC、HTTP、其他抽象为数据源为数据的读取和写入提供支持写进核心职责的原因——它体现的是对连接资源的统一建模能力与架构扩展性思维。五、小结本章将连接抽象为数据源是整个 API 网关通信组件中承上启下的一环承上它建立在第 13 章 Netty 会话、RPC 泛化调用、分治重构的基础上把连接从具体实现中提炼出来启下它直接支撑了第 5 章 HTTP 参数解析参数最终要按数据源调用方式封装与第 6 章执行器封装对数据源调用的统一处理面向扩展通过DataSourceFactory / DataSource / Executor / IGenericReference的抽象组合网关可以平滑地接入不同厂商的 RPC、HTTP、WebService甚至通过 SPI 扩展自定义连接资源同时为连接池化预留了实现空间。对于读者而言本章最有价值的收获不是某一段泛化调用代码而是**把远程连接当作数据源统一建模这一可复用的架构思维**——它同样适用于中间件、网关、平台类系统的设计。继续往下走第5章HTTP请求参数解析 将在此基础上处理 GET/POST 与不同 Content-Type 的参数解析最终把参数喂给抽象好的数据源完成一次完整的网关调用。赞分享文档教程后端【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址https://gitcode.com/gh_mirrors/code/CodeGuide点击查看免费下载相关推荐用Jetpack Glance打造MoeList今日更新桌面小组件从布局到点击跳转完整教程用Jetpack Glance打造MoeList今日更新桌面小组件从布局到点击跳转完整教程 MoeList 是一款非官方的 MyAnimeListMAL文档教程后端如何高效使用Artisan咖啡烘焙软件完整专业烘焙指南如何高效使用Artisan咖啡烘焙软件完整专业烘焙指南 Artisan是世界上最受信赖的开源咖啡烘焙软件帮助烘焙师记录、分析和控制烘焙过程。这款强大的工具能文档教程后端Blender For Unreal Engine摄像机导出完全攻略从Blender到Unreal SequencerBlender For Unreal Engine摄像机导出完全攻略从Blender到Unreal Sequencer Blender For Unreal开发工具游戏开发上一篇开源项目推荐mission-peace/interview下一篇StarRocks rtrim 字符串函数完全指南语法、参数、实战与底层实现创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价