Apache ShenYu 架构学习指南

本文涉及的产品
函数计算FC,每月15万CU 3个月
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
简介: Apache ShenYu 是一款高性能、插件化的微服务API网关,基于Spring WebFlux + Reactor 构建,支持多协议、动态配置与实时数据同步。本指南以通俗类比和实战路径,带你深入理解其架构设计、核心流程与源码实现,助力快速掌握并参与贡献。

嘿,欢迎来到 Apache ShenYu 的学习之旅! 👋
这不是一份枯燥的技术文档,而是你的私人教练笔记。我会像朋友一样,带你从零开始,逐步理解这个高性能 API 网关的设计精髓。


第一部分:项目架构深度解析 🔍

1. 项目架构概览

🎯 用通俗的类比理解 ShenYu

想象一个繁忙的国际机场 ✈️:

  • ShenYu Gateway(网关) = 机场的航站楼,所有乘客(请求)必须经过这里
  • Plugin(插件) = 安检、海关、检票等各个环节,每个环节各司其职
  • Admin(管理后台) = 机场调度中心,实时配置航班、闸口规则
  • Selector & Rule(选择器与规则) = 航班指示牌,告诉每位乘客该去哪个登机口
  • Data Sync(数据同步) = 实时广播系统,让所有地方都知道最新的航班信息

📊 核心设计特征

ShenYu 是一个高性能、可扩展的微服务 API 网关,它的设计哲学是:

  1. 插件化架构 - 一切皆插件,按需加载
  2. 责任链模式 - 请求像流水线一样依次经过各个插件
  3. 动态配置 - 无需重启即可实时更新规则
  4. 多协议支持 - HTTP、Dubbo、gRPC、WebSocket...一网打尽
  5. 响应式编程 - 基于 Spring WebFlux + Reactor 的异步非阻塞

🆚 与其他网关的对比

如果你了解 KongZuul,那么:

  • Kong(基于 Nginx + Lua) → ShenYu(基于 Java + Netty)
  • Kong 的插件需要 Lua 编程 → ShenYu 的插件用熟悉的 Java
  • Zuul 1.x 是同步阻塞 → ShenYu 是异步响应式,性能更好
  • Spring Cloud Gateway 功能较轻 → ShenYu 提供完整的治理能力

🛠️ 技术栈核心组件

框架层:
  - Spring Boot: 3.3.1
  - Spring WebFlux: 响应式Web框架
  - Reactor: 响应式编程库
  - Netty: 高性能网络通信

存储层:
  - H2/MySQL/PostgreSQL/Oracle: 元数据存储
  - ZooKeeper/Nacos/Etcd/Consul: 配置中心(可选)

通信层:
  - WebSocket: 默认数据同步方式
  - gRPC: RPC通信支持
  - Dubbo/Motan/SOFA: 多种RPC协议

工具层:
  - MyBatis: 数据访问
  - Disruptor: 高性能队列
  - Caffeine: 本地缓存
  - Guava: 工具库

🌐 外部系统集成

ShenYu 可以对接:

  • 注册中心:Zookeeper、Nacos、Eureka、Consul、Etcd
  • 配置中心:Apollo、Nacos、Polaris
  • 监控系统:Prometheus(通过 metrics 插件)
  • 链路追踪:集成 OpenTelemetry(需配置)
  • 消息队列:Kafka、RocketMQ(用于日志收集)

🔄 架构流程描述

一个典型的 HTTP 请求在 ShenYu 中的旅程:

graph LR
    A[客户端请求] --> B[ShenYu Bootstrap:9195]
    B --> C{GlobalPlugin<br/>全局处理}
    C --> D{Selector匹配<br/>粗粒度路由}
    D --> E{Rule匹配<br/>细粒度规则}
    E --> F[插件链执行]
    F --> G[RateLimiter<br/>限流]
    G --> H[Sign<br/>鉴权]
    H --> I[Divide/Dubbo<br/>路由转发]
    I --> J[后端服务]
    J --> K[Response<br/>响应处理]
    K --> L[返回客户端]

    M[Admin:9095] -.配置推送.-> B
    M --> N[(MySQL/H2<br/>元数据)]
    M -.WebSocket/ZK.-> B

关键点说明

  1. 请求进入 ShenyuWebHandler(核心处理器)
  2. order 顺序执行插件链
  3. 每个插件可选择是否处理当前请求(通过 skip()
  4. Selector 决定大方向(如匹配到 /api/** 路由)
  5. Rule 决定具体策略(如负载均衡、超时时间)
  6. 代理插件(如 DividePlugin)完成最终转发

2. 目录结构与核心流程

📁 项目目录组织逻辑

ShenYu 采用 Maven 多模块 结构,按功能模块清晰划分:

shenyu/
├── shenyu-admin/              # 🎛️ 管理后台(9095端口)
│   ├── mapper/                  # MyBatis 数据访问层
│   ├── service/                 # 业务逻辑层
│   ├── controller/              # REST API 接口
│   └── listener/                # 数据变更监听器
│
├── shenyu-bootstrap/          # 🚀 网关启动模块(9195端口)
│   └── application.yml          # 【第一个要看的配置文件】
│
├── shenyu-web/                # 🌐 Web处理核心
│   ├── handler/                 # ShenyuWebHandler(请求总入口)
│   ├── filter/                  # 前置过滤器(跨域、健康检查等)
│   └── loader/                  # 插件动态加载器
│
├── shenyu-plugin/             # 🔌 插件生态(40+插件)
│   ├── shenyu-plugin-api/       # 插件接口定义
│   ├── shenyu-plugin-base/      # 插件基础类
│   ├── shenyu-plugin-divide/    # HTTP代理插件
│   ├── shenyu-plugin-dubbo/     # Dubbo代理插件
│   ├── shenyu-plugin-ratelimiter/ # 限流插件
│   └── shenyu-plugin-sign/      # 签名认证插件
│
├── shenyu-sync-data-center/   # 🔄 数据同步中心
│   ├── shenyu-sync-data-websocket/ # WebSocket同步(默认)
│   ├── shenyu-sync-data-zookeeper/ # ZooKeeper同步
│   └── shenyu-sync-data-nacos/     # Nacos同步
│
├── shenyu-client/             # 📲 客户端SDK(业务系统接入)
│   ├── shenyu-client-http/      # HTTP服务接入
│   ├── shenyu-client-dubbo/     # Dubbo服务接入
│   └── shenyu-client-grpc/      # gRPC服务接入
│
├── shenyu-common/             # 🛠️ 公共工具模块
│   └── dto/                     # 核心数据传输对象(RuleData、SelectorData)
│
├── shenyu-spi/                # 🔧 SPI机制实现
├── shenyu-register-center/    # 📝 服务注册中心
├── shenyu-loadbalancer/       # ⚖️ 负载均衡算法
└── shenyu-examples/           # 💡 示例代码(强烈推荐学习)
    ├── shenyu-examples-http/    # HTTP服务接入示例
    ├── shenyu-examples-dubbo/   # Dubbo服务接入示例
    └── shenyu-examples-grpc/    # gRPC服务接入示例

👀 关键文件定位表

文件路径 作用 阅读优先级
shenyu-bootstrap/src/main/resources/application.yml 网关核心配置 ⭐⭐⭐⭐⭐ 必读
shenyu-web/...//ShenyuWebHandler.java 请求处理总入口 ⭐⭐⭐⭐⭐
shenyu-plugin-api/.../ShenyuPlugin.java 插件接口定义 ⭐⭐⭐⭐
shenyu-common/dto/RuleData.java 规则数据结构 ⭐⭐⭐⭐
shenyu-admin/.../ShenyuAdminBootstrap.java 管理后台启动类 ⭐⭐⭐
db/init/schema.sql 数据库表结构 ⭐⭐⭐

📦 模块依赖关系

graph TB
    A[shenyu-bootstrap] --> B[shenyu-web]
    B --> C[shenyu-plugin-base]
    C --> D[shenyu-plugin-api]
    B --> E[shenyu-sync-data-center]
    A --> F[shenyu-spring-boot-starter]

    G[shenyu-admin] --> H[shenyu-common]
    G --> I[shenyu-admin-listener]

    C --> H
    E --> H

    J[业务服务] --> K[shenyu-client]
    K --> H

依赖说明

  • 核心依赖是 单向的,从上层到下层
  • shenyu-common 被所有模块依赖,是基础模块
  • shenyu-adminshenyu-bootstrap 是两个独立的应用,互不依赖

🔥 典型业务流程:HTTP请求代理

让我们追踪一个最常见的场景:/api/user/123 代理到后端服务

步骤拆解

// ① 请求到达 ShenyuWebHandler
// 位置: shenyu-web/src/main/java/org/apache/shenyu/web/handler/ShenyuWebHandler.java:123
public Mono<Void> handle(ServerWebExchange exchange) {
   
    before(exchange);  // 记录开始时间
    return new DefaultShenyuPluginChain(plugins).execute(exchange);
}

// ② 插件链开始执行
// 位置: ShenyuWebHandler.java:289
public Mono<Void> execute(ServerWebExchange exchange) {
   
    if (this.index < plugins.size()) {
   
        ShenyuPlugin plugin = plugins.get(this.index++);
        if (!plugin.skip(exchange)) {
     // 判断是否跳过
            return plugin.execute(exchange, this);
        }
    }
    return Mono.empty();
}

// ③ GlobalPlugin - 构建 ShenyuContext
// 位置: shenyu-plugin/shenyu-plugin-global/.../GlobalPlugin.java
// 作用: 解析请求,生成上下文对象,存入 exchange.attributes

// ④ DividePlugin - HTTP代理插件
// 位置: shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/.../DividePlugin.java
protected Mono<Void> doExecute(ServerWebExchange exchange, 
                                 ShenyuPluginChain chain, 
                                 SelectorData selector, 
                                 RuleData rule) {
   
    // 1. 获取后端服务列表
    List<Upstream> upstreams = loadUpstreams(selector);
    // 2. 负载均衡选择一个
    Upstream upstream = loadBalancer.select(upstreams, exchange);
    // 3. 构建目标 URL
    String targetUrl = buildRealURL(upstream, exchange);
    // 4. 发起 HTTP 调用
    return httpClient.request(targetUrl, exchange);
}

数据流动路径

客户端请求
  └→ Netty接收(端口9195)
     └→ Spring WebFlux DispatcherHandler
        └→ ShenyuWebHandler.handle()
           └→ GlobalPlugin(生成ShenyuContext)
              └→ SignPlugin(验证签名)
                 └→ WafPlugin(安全检查)
                    └→ RateLimiterPlugin(限流)
                       └→ DividePlugin(HTTP代理)
                          └→ WebClient发起请求
                             └→ 后端服务(如 127.0.0.1:8080)

📊 核心数据结构流程图

sequenceDiagram
    participant Client as 客户端
    participant Gateway as ShenYu Gateway
    participant Plugin as 插件链
    participant Backend as 后端服务
    participant Admin as ShenYu Admin

    Admin->>Gateway: ①推送配置(WebSocket)
    Note over Gateway: 更新内存缓存

    Client->>Gateway: ②发送请求 /api/user/123
    Gateway->>Plugin: ③执行插件链

    Plugin->>Plugin: ④GlobalPlugin: 构建上下文
    Plugin->>Plugin: ⑤SignPlugin: 鉴权
    Plugin->>Plugin: ⑥RateLimiterPlugin: 限流
    Plugin->>Plugin: ⑦DividePlugin: 选择后端

    Plugin->>Backend: ⑧代理转发请求
    Backend-->>Plugin: ⑨返回响应
    Plugin-->>Gateway: ⑩处理响应
    Gateway-->>Client: ⑪返回结果

🎯 实现文件索引

流程阶段 核心文件
请求接收 shenyu-web/handler/ShenyuWebHandler.java
全局处理 shenyu-plugin/shenyu-plugin-global/GlobalPlugin.java
鉴权签名 shenyu-plugin/shenyu-plugin-security/shenyu-plugin-sign/SignPlugin.java
限流控制 shenyu-plugin/shenyu-plugin-fault-tolerance/shenyu-plugin-ratelimiter/RateLimiterPlugin.java
HTTP代理 shenyu-plugin/shenyu-plugin-proxy/shenyu-plugin-divide/DividePlugin.java
负载均衡 shenyu-loadbalancer/src/main/java/...//LoadBalancer.java
数据同步 shenyu-sync-data-center/shenyu-sync-data-websocket/.../WebsocketSyncDataService.java

3. 代码结构观察

🏗️ 代码组织模式

ShenYu 的代码组织遵循以下模式:

1. 插件采用模板方法模式

// 抽象插件基类
public abstract class AbstractShenyuPlugin implements ShenyuPlugin {
   

    @Override
    public Mono<Void> execute(ServerWebExchange exchange, ShenyuPluginChain chain) {
   
        // ① 模板方法:定义执行骨架
        SelectorData selector = matchSelector(exchange);  // 匹配选择器
        if (selector == null) {
   
            return chain.execute(exchange);
        }

        RuleData rule = matchRule(exchange, selector);    // 匹配规则
        if (rule == null) {
   
            return chain.execute(exchange);
        }

        // ② 子类实现具体逻辑
        return doExecute(exchange, chain, selector, rule);
    }

    // 留给子类实现
    protected abstract Mono<Void> doExecute(...);
}

2. 数据缓存采用单例模式

// 位置: shenyu-plugin/shenyu-plugin-base/cache/BaseDataCache.java
public final class BaseDataCache {
   

    private static final BaseDataCache INSTANCE = new BaseDataCache();

    // 插件数据缓存
    private final ConcurrentMap<String, PluginData> PLUGIN_MAP = new ConcurrentHashMap<>();

    // 选择器数据缓存
    private final ConcurrentMap<String, List<SelectorData>> SELECTOR_MAP = new ConcurrentHashMap<>();

    public static BaseDataCache getInstance() {
   
        return INSTANCE;
    }
}

3. 数据同步采用观察者模式

// 监听数据变化
public interface DataChangedListener {
   
    void onPluginChanged(List<PluginData> changed);
    void onSelectorChanged(List<SelectorData> changed);
    void onRuleChanged(List<RuleData> changed);
}

// Admin 推送数据时通知所有监听器
publisher.publishEvent(new DataChangedEvent(...));

🎨 设计模式识别

设计模式 应用场景 代码位置
责任链模式 插件链执行 ShenyuPluginChain
模板方法模式 插件抽象基类 AbstractShenyuPlugin
单例模式 数据缓存 BaseDataCache
观察者模式 数据变更通知 DataChangedListener
工厂模式 负载均衡器创建 LoadBalancerFactory
策略模式 多种负载均衡算法 LoadBalancer 接口
Builder模式 DTO对象构建 RuleData.Builder
SPI机制 插件扩展 @SPI 注解

🔍 代码质量观察

✅ 优秀实践

  1. 清晰的职责划分 - 每个模块功能单一,边界清晰
  2. 充分的抽象 - 接口与实现分离,易于扩展
  3. 完善的单元测试 - 核心模块测试覆盖率高
  4. 统一的代码风格 - 遵循 Checkstyle 规范
  5. 丰富的示例代码 - shenyu-examples 目录提供大量实例

⚠️ 需要关注的点

  1. 响应式编程学习曲线 - 大量使用 Reactor,新手可能不适应
  2. 配置项较多 - application.yml 配置项众多,需逐步理解
  3. 模块间通信复杂 - Admin 与 Gateway 的数据同步有多种方式

💡 学习机会(潜在改进点)

这些点不是批评,而是你深入学习的好方向:

  1. TODO 注释探索

    # 搜索 TODO/FIXME
    grep -r "TODO\|FIXME" shenyu-*/src --include="*.java"
    
  2. 性能优化思考点

    • 插件链的执行性能(是否可以并行处理?)
    • 选择器和规则的匹配算法(Trie树优化)
    • 本地缓存的过期策略
  3. 代码重构练习

    • 尝试提取重复的判空逻辑
    • 将长方法(>50行)拆分为小方法
    • 优化嵌套层级深的代码

第二部分:技能需求清单 📚

1. 基础技能要求

🎓 编程语言和框架

Java 核心(必须)

  • ✅ Java 17 语法特性(Records、Switch表达式、Text Blocks)
  • ✅ Lambda 表达式与 Stream API
  • ✅ 并发编程(CompletableFuture、线程池)
  • ✅ 反射与注解

Spring 生态(必须)

  • ✅ Spring Boot 3.x 自动配置原理
  • ✅ Spring WebFlux 响应式编程(重点!)
  • ✅ Spring AOP 切面编程
  • ✅ Spring 依赖注入(DI)和控制反转(IoC)

响应式编程(重点难点)

// Reactor 核心概念必须掌握
Mono<String> mono = Mono.just("Hello");     // 0-1个元素
Flux<Integer> flux = Flux.range(1, 5);      // 0-N个元素

// 常用操作符
mono.map(s -> s.toUpperCase())              // 转换
    .flatMap(s -> callAnotherService(s))    // 异步调用
    .filter(s -> s.length() > 5)            // 过滤
    .doOnNext(System.out::println)          // 副作用
    .subscribe();                            // 触发执行

🔧 具体版本要求

依赖 版本 说明
JDK 17+ 必须,使用了 Java 17 特性
Spring Boot 3.3.1 核心框架
Reactor (由Spring Boot管理) 响应式编程库
Netty (由Spring Boot管理) 网络通信层
MyBatis 3.0.3 Admin 数据访问
Dubbo 3.2.14 Dubbo协议支持
gRPC 1.65.1 gRPC协议支持

⚠️ 版本兼容性提示

  • ShenYu 2.7.x 要求 JDK 17+,不兼容 JDK 8
  • 如果你的业务系统是 JDK 8,只需升级 ShenYu Gateway 即可,业务系统无需升级

🛠️ 基础工具和概念

必备工具

  • ✅ Maven(项目构建)
  • ✅ Git(版本控制)
  • ✅ Docker(容器部署)
  • ✅ Postman/Curl(接口测试)
  • ✅ IDEA(推荐IDE)

数据库知识

  • ✅ MySQL 基本操作
  • ✅ SQL 查询与索引优化
  • ✅ 数据库连接池(HikariCP)

2. 进阶技能要求

🏛️ 架构模式和设计原则

必须理解的模式

  1. 微服务架构 - ShenYu 本身就是微服务基础设施
  2. 插件化架构 - 核心功能以插件形式组织
  3. 事件驱动架构 - 数据变更通过事件传播

设计原则(SOLID)

  • 单一职责 - 每个插件只做一件事
  • 开闭原则 - 通过插件扩展,而不是修改核心代码
  • 依赖倒置 - 依赖抽象(ShenyuPlugin接口),而非具体实现

🌐 领域特定知识

API 网关领域

  • 路由转发、负载均衡、限流熔断
  • 灰度发布、A/B测试
  • API 鉴权与签名
  • 请求/响应转换

RPC 协议理解

  • HTTP/HTTPS、HTTP/2
  • Dubbo 序列化与通信机制
  • gRPC Protobuf
  • WebSocket 长连接

服务治理概念

  • 服务注册与发现
  • 配置中心
  • 链路追踪
  • 监控告警

3. 技能掌握程度建议

🌱 初学者(1-2周目标)

你应该能

  • 成功启动 Admin 和 Bootstrap
  • 通过 Admin 界面配置一个简单的 HTTP 路由
  • 理解 Selector 和 Rule 的区别
  • 阅读 GlobalPluginDividePlugin 源码

学习路径

  1. 跟着 Quick Start 运行起来
  2. 阅读官方文档的"核心概念"部分
  3. 尝试修改 application.yml 配置
  4. 在 IDEA 中打断点,跟踪一次完整请求

🚀 有经验的开发者(1-2月目标)

你应该能

  • 自定义开发一个简单插件
  • 理解数据同步的多种实现方式
  • 配置 Dubbo/gRPC 代理
  • 排查常见问题(端口冲突、配置错误)

学习路径

  1. 深入理解插件链执行机制
  2. 阅读 3-5 个核心插件源码
  3. 参考 shenyu-examples 实现业务接入
  4. 学习 SPI 机制和自定义扩展

🏆 进阶贡献者(3月+目标)

你应该能

  • 为 ShenYu 贡献代码(修复 Bug 或新功能)
  • 理解整体架构设计权衡
  • 优化性能瓶颈
  • 设计企业级部署方案

学习路径

  1. 完整阅读核心模块源码
  2. 参与社区讨论,了解设计决策
  3. 尝试提交 Pull Request
  4. 研究性能测试与调优

第三部分:学习路径规划 🎯

1. 项目运行入口定位(快速上手)

🚀 一键启动指南(预计 30 分钟)

方式一:Docker 快速启动(推荐新手)

# ① 创建 Docker 网络
docker network create shenyu

# ② 启动 Admin(管理后台)
docker pull apache/shenyu-admin
docker run -d --name shenyu-admin \
  -p 9095:9095 \
  --net shenyu \
  apache/shenyu-admin

# ③ 启动 Bootstrap(网关)
docker pull apache/shenyu-bootstrap
docker run -d --name shenyu-bootstrap \
  -p 9195:9195 \
  -e "shenyu.local.enabled=true" \
  -e "SHENYU_SYNC_WEBSOCKET_URLS=ws://shenyu-admin:9095/websocket" \
  --net shenyu \
  apache/shenyu-bootstrap

# ④ 验证成功
# 访问 http://localhost:9095 (账号/密码: admin/123456)
# 网关地址: http://localhost:9195

方式二:源码本地启动(推荐深入学习)

# ① 克隆代码
git clone https://github.com/apache/shenyu.git
cd shenyu

# ② 编译项目(跳过测试加速)
mvn clean install -DskipTests -Dmaven.javadoc.skip=true

# ③ 初始化数据库(选择 H2 或 MySQL)
# 使用 H2(无需额外安装):
#   Admin 启动时会自动初始化

# 使用 MySQL:
mysql -uroot -p < db/init/mysql/schema.sql

# ④ 启动 Admin
cd shenyu-admin
mvn spring-boot:run
# 或用 IDEA 运行 ShenyuAdminBootstrap.main()

# ⑤ 启动 Bootstrap(新终端)
cd shenyu-bootstrap
mvn spring-boot:run
# 或用 IDEA 运行 ShenyuBootstrapApplication.main()

# ⑥ 验证成功
curl http://localhost:9095/actuator/health  # Admin 健康检查
curl http://localhost:9195/actuator/health  # Gateway 健康检查

⚙️ 环境配置清单

必备软件

软件 版本要求 下载地址
JDK 17+ https://adoptium.net/
Maven 3.6+ https://maven.apache.org/
MySQL 5.7+(可选) https://dev.mysql.com/downloads/
Docker 20+(可选) https://www.docker.com/

配置检查清单

# ✅ 检查 Java 版本
java -version  # 应显示 17 或更高

# ✅ 检查 Maven
mvn -version

# ✅ 检查端口占用
netstat -an | findstr "9095"  # Windows
lsof -i:9095                   # Mac/Linux

# ✅ 配置 Maven 镜像加速(国内用户)
# 编辑 ~/.m2/settings.xml,添加阿里云镜像

⚠️ 常见配置陷阱及解决方案

问题 现象 解决方案
端口冲突 Address already in use 修改 application.yml 中的 server.port
JDK版本不对 Unsupported class file major version 确保使用 JDK 17+
数据库连接失败 Could not connect to database 检查 application-mysql.yml 配置
WebSocket 连接失败 Gateway 无法同步配置 确认 Admin 的 9095 端口可访问
内存不足 OutOfMemoryError 增加 JVM 参数 -Xmx2g

✅ 验证成功标志

1. Admin 启动成功

# 日志中看到:
Started ShenyuAdminBootstrap in xx seconds

# 浏览器访问:
http://localhost:9095

# 能看到登录界面 → 成功!
# 默认账号: admin / 123456

2. Bootstrap 启动成功

# 日志中看到:
Netty Http Server start success, on port : 9195

# 命令行测试:
curl http://localhost:9195/actuator/health

# 返回 {"status":"UP"} → 成功!

3. 数据同步成功

# Bootstrap 日志中看到:
websocket sync data completed

# 在 Admin 界面"系统管理 -> 插件管理"中,
# 能看到多个插件(divide、dubbo、sign等)→ 成功!

4. 完整链路测试

# 启动一个测试后端服务(端口 8080)
# 在 Admin 中配置一个 divide 插件规则
# 通过网关访问:
curl http://localhost:9195/your-api-path

# 能正常返回后端响应 → 完整链路打通!

2. 循序渐进学习计划(四阶段法)

📅 阶段一:环境搭建和项目启动(1-2 天)

目标:成功运行项目并能打个断点 🎯

任务清单

  • [ ] 安装 JDK 17 和 Maven
  • [ ] 克隆代码并编译成功
  • [ ] 启动 Admin 和 Bootstrap
  • [ ] 登录 Admin 后台,浏览功能菜单
  • [ ] 在 IDEA 中给 ShenyuWebHandler.handle() 打断点
  • [ ] 发送一个请求,断点生效,观察调用栈

实战练习

# 1. 启动项目后,运行示例服务
cd shenyu-examples/shenyu-examples-http
mvn spring-boot:run

# 2. 在 Admin 中配置路由
插件列表 -> divide -> 选择器 -> 新增
  名称: test-selector
  匹配方式: 前缀匹配
  条件: uri = /http/**

规则列表 -> 新增
  名称: test-rule
  匹配条件: uri = /http/**
  处理: {
   "loadBalance":"random","retry":0}

# 3. 测试转发
curl http://localhost:9195/http/test/findByUserId?userId=1

# 4. 观察日志,理解请求流程

学习资源


📅 阶段二:核心流程理解(3-5 天)

目标:追踪一个完整业务流程,画出自己的流程图 🎯

任务清单

  • [ ] 理解 Selector 和 Rule 的作用
  • [ ] 阅读 ShenyuWebHandler 源码
  • [ ] 阅读 GlobalPluginDividePlugin 源码
  • [ ] 使用调试器逐步跟踪请求
  • [ ] 画出插件链执行流程图
  • [ ] 理解数据同步机制(WebSocket)

核心文件阅读顺序

// ① 请求入口
shenyu-web/handler/ShenyuWebHandler.java
  ├─ handle()          // 总入口
  └─ DefaultShenyuPluginChain.execute()  // 插件链

// ② 插件接口
shenyu-plugin-api/ShenyuPlugin.java
  ├─ execute()         // 执行逻辑
  ├─ skip()            // 是否跳过
  └─ getOrder()        // 执行顺序

// ③ 插件基类
shenyu-plugin-base/AbstractShenyuPlugin.java
  ├─ execute()         // 模板方法
  ├─ matchSelector()   // 选择器匹配
  ├─ matchRule()       // 规则匹配
  └─ doExecute()       // 子类实现

// ④ HTTP代理插件
shenyu-plugin-divide/DividePlugin.java
  └─ doExecute()       // 负载均衡+HTTP调用

// ⑤ 数据缓存
shenyu-plugin-base/cache/BaseDataCache.java
  ├─ PLUGIN_MAP        // 插件缓存
  ├─ SELECTOR_MAP      // 选择器缓存
  └─ RULE_MAP          // 规则缓存

实战练习

// 1. 自己实现一个简单的"日志打印插件"
@Component
public class MyLogPlugin implements ShenyuPlugin {
   

    @Override
    public Mono<Void> execute(ServerWebExchange exchange, ShenyuPluginChain chain) {
   
        String path = exchange.getRequest().getPath().value();
        System.out.println("===== 请求路径: " + path + " =====");
        return chain.execute(exchange);  // 继续执行下一个插件
    }

    @Override
    public int getOrder() {
   
        return 0;  // 最先执行
    }

    @Override
    public String named() {
   
        return "myLog";
    }
}

// 2. 启动项目,观察日志输出

📅 阶段三:模块深入和定制开发(1-2 周)

目标:能修改或扩展一个现有功能 🎯

任务清单

  • [ ] 深入理解 3-5 个插件源码(如 Sign、RateLimiter、Dubbo)
  • [ ] 理解 SPI 机制,查看 @SPI 注解的使用
  • [ ] 尝试自定义一个负载均衡算法
  • [ ] 学习数据同步的其他方式(Zookeeper、Nacos)
  • [ ] 接入一个 Dubbo 服务到网关

深入学习插件

插件 功能 学习重点
SignPlugin API签名验证 参数提取、签名算法
RateLimiterPlugin 限流 Redis+Lua脚本、令牌桶算法
DubboPlugin Dubbo代理 泛化调用、参数映射
HystrixPlugin 熔断 Hystrix 命令封装
WafPlugin 安全防护 黑白名单、SQL注入检测

实战练习:自定义负载均衡器

// 1. 实现 LoadBalancer 接口
@Join  // SPI 标记
public class MyWeightedLoadBalancer implements LoadBalancer {
   

    @Override
    public Upstream select(List<Upstream> upstreams, String ip) {
   
        // 实现加权随机算法
        int totalWeight = upstreams.stream()
            .mapToInt(Upstream::getWeight)
            .sum();

        int random = ThreadLocalRandom.current().nextInt(totalWeight);
        for (Upstream upstream : upstreams) {
   
            random -= upstream.getWeight();
            if (random < 0) {
   
                return upstream;
            }
        }
        return upstreams.get(0);
    }
}

// 2. 在 META-INF/shenyu/ 目录下创建 SPI 文件
// org.apache.shenyu.loadbalancer.spi.LoadBalancer
myWeighted=com.example.MyWeightedLoadBalancer

// 3. 在规则配置中使用
{
   "loadBalance":"myWeighted"}

📅 阶段四:架构理解和贡献指南(2 周+)

目标:能理解技术选型原因,并尝试修复一个简单 issue 🎯

任务清单

  • [ ] 阅读完整架构设计文档
  • [ ] 理解为什么选择 Reactor 而不是传统 Servlet
  • [ ] 理解为什么使用 Disruptor 队列
  • [ ] 参与社区讨论,提问和回答问题
  • [ ] 在 GitHub 上找一个 good first issue 并尝试修复
  • [ ] 提交你的第一个 Pull Request

架构设计权衡

技术选型 原因 权衡
Reactor 异步非阻塞,高并发 学习曲线陡峭
Netty 高性能网络通信 配置复杂
Disruptor 无锁队列,低延迟 内存占用较大
ConcurrentHashMap 本地缓存,极速读取 集群间需同步
WebSocket 实时推送配置 需保持长连接

贡献指南

# 1. Fork 项目到你的 GitHub

# 2. 克隆你的 Fork
git clone https://github.com/YOUR_USERNAME/shenyu.git
cd shenyu

# 3. 创建分支
git checkout -b fix-issue-1234

# 4. 修改代码并测试
# 确保通过所有单元测试
mvn test

# 5. 提交代码
git add .
git commit -m "fix: 修复 issue #1234 的问题"
git push origin fix-issue-1234

# 6. 在 GitHub 上创建 Pull Request

# 7. 等待 Code Review

3. 学习路径流程图

graph TB
    Start([开始学习 ShenYu]) --> Stage1{阶段一<br/>环境搭建}

    Stage1 -->|1-2天| Check1{能成功启动?}
    Check1 -->|否| Trouble1[查看常见问题]
    Trouble1 --> Stage1
    Check1 -->|是| Stage2{阶段二<br/>核心流程理解}

    Stage2 -->|3-5天| Check2{能追踪请求流程?}
    Check2 -->|否| Doc1[阅读官方文档]
    Doc1 --> Stage2
    Check2 -->|是| Stage3{阶段三<br/>模块深入}

    Stage3 -->|1-2周| Check3{能自定义插件?}
    Check3 -->|否| Code1[参考示例代码]
    Code1 --> Stage3
    Check3 -->|是| Stage4{阶段四<br/>架构理解}

    Stage4 -->|2周+| Check4{能贡献代码?}
    Check4 -->|否| Community[参与社区讨论]
    Community --> Stage4
    Check4 -->|是| End([成为 ShenYu 专家!])

    style Start fill:#e1f5e1
    style End fill:#ffe1e1
    style Check1 fill:#fff9e1
    style Check2 fill:#fff9e1
    style Check3 fill:#fff9e1
    style Check4 fill:#fff9e1

第四部分:实践建议和进阶指导 💡

1. 调试技巧和常见陷阱

🐛 调试技巧

技巧1:善用日志级别

# application.yml
logging:
  level:
    org.apache.shenyu: debug           # ShenYu 核心日志
    org.apache.shenyu.plugin: trace    # 插件详细日志
    reactor.netty: debug                # Netty 网络日志

技巧2:关键断点位置

// ① 请求入口
ShenyuWebHandler.handle()  
  → 观察请求开始

// ② 插件执行
DefaultShenyuPluginChain.execute()  
  → 观察插件链

// ③ 选择器匹配
AbstractShenyuPlugin.matchSelector()  
  → 观察路由匹配

// ④ 后端调用
DividePlugin.doExecute()  
  → 观察代理转发

技巧3:Reactor 调试

// 开启 Reactor 调试模式(启动类中)
static {
   
    Hooks.onOperatorDebug();  // 会显示完整的异步调用栈
}

⚠️ 常见陷阱(Top 5)

1. 配置未生效

❌ 问题: 修改了 Admin 配置,但 Gateway 没反应
✅ 排查:
  - 检查 WebSocket 连接是否正常
  - 查看 Gateway 日志是否有 "sync data completed"
  - 检查插件是否启用(Admin -> 插件管理 -> 状态)

2. 端口冲突

❌ 问题: Address already in use: 9095
✅ 解决:
  # Windows
  netstat -ano | findstr "9095"
  taskkill /PID <PID> /F

  # Linux/Mac
  lsof -i:9095
  kill -9 <PID>

3. Selector/Rule 不匹配

❌ 问题: 请求返回 404,但后端服务正常
✅ 排查:
  - 检查 Selector 的匹配条件(uri、header、method等)
  - 查看 Rule 的条件是否覆盖当前请求
  - 注意匹配顺序(sort字段)

4. Dubbo 泛化调用失败

❌ 问题: No provider available
✅ 排查:
  - 确认 Dubbo 服务已注册到注册中心
  - 检查 metadata(服务元数据)是否正确
  - 确认网络连通性

5. 内存溢出

❌ 问题: OutOfMemoryError: Java heap space
✅ 解决:
  # 增加堆内存
  java -Xms2g -Xmx4g -jar shenyu-bootstrap.jar

  # 或在 IDEA 中设置 VM Options:
  -Xms2g -Xmx4g -XX:+HeapDumpOnOutOfMemoryError

2. 扩展练习建议

🌟 练习1:修改响应头(难度:⭐)

目标:为所有响应添加自定义 Header

@Component
public class CustomHeaderPlugin implements ShenyuPlugin {
   

    @Override
    public Mono<Void> execute(ServerWebExchange exchange, ShenyuPluginChain chain) {
   
        return chain.execute(exchange).doFinally(signal -> {
   
            exchange.getResponse().getHeaders().add("X-Powered-By", "ShenYu");
        });
    }

    @Override
    public int getOrder() {
   
        return Integer.MAX_VALUE;  // 最后执行
    }
}

🌟 练习2:实现IP黑名单(难度:⭐⭐)

目标:拦截黑名单 IP 的请求

@Component
public class IpBlacklistPlugin implements ShenyuPlugin {
   

    private final Set<String> blacklist = Set.of("192.168.1.100", "10.0.0.50");

    @Override
    public Mono<Void> execute(ServerWebExchange exchange, ShenyuPluginChain chain) {
   
        String clientIp = getClientIp(exchange);
        if (blacklist.contains(clientIp)) {
   
            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
            return exchange.getResponse().setComplete();
        }
        return chain.execute(exchange);
    }

    private String getClientIp(ServerWebExchange exchange) {
   
        return exchange.getRequest()
            .getHeaders()
            .getFirst("X-Forwarded-For");
    }
}

🌟 练习3:添加数据库表(难度:⭐⭐⭐)

目标:为 API 调用添加计数统计功能

-- 1. 创建表
CREATE TABLE api_stat (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    api_path VARCHAR(255),
    call_count INT DEFAULT 0,
    last_call_time DATETIME
);

-- 2. 实现统计插件
@Component
public class ApiStatPlugin implements ShenyuPlugin {

    @Autowired
    private ApiStatMapper mapper;

    @Override
    public Mono<Void> execute(ServerWebExchange exchange, ShenyuPluginChain chain) {
        String path = exchange.getRequest().getPath().value();

        // 异步更新统计(不阻塞主流程)
        Mono.fromRunnable(() -> mapper.incrementCount(path))
            .subscribeOn(Schedulers.boundedElastic())
            .subscribe();

        return chain.execute(exchange);
    }
}

🌟 练习4:动态路由切换(难度:⭐⭐⭐⭐)

目标:根据请求头实现灰度发布

@Component
public class GrayReleasePlugin extends AbstractShenyuPlugin {
   

    @Override
    protected Mono<Void> doExecute(ServerWebExchange exchange, 
                                     ShenyuPluginChain chain, 
                                     SelectorData selector, 
                                     RuleData rule) {
   
        String version = exchange.getRequest().getHeaders().getFirst("X-Version");

        List<Upstream> upstreams = getUpstreams(selector);

        // 根据版本选择后端
        Upstream target = upstreams.stream()
            .filter(u -> matchVersion(u, version))
            .findFirst()
            .orElseGet(() -> upstreams.get(0));  // 降级到默认版本

        // 设置目标地址
        exchange.getAttributes().put("targetUrl", buildUrl(target, exchange));
        return chain.execute(exchange);
    }
}

3. 参与贡献的途径

🤝 社区位置

🔍 寻找 Good First Issue

# 1. 访问 GitHub Issues
https://github.com/apache/shenyu/issues

# 2. 筛选标签
Label: good first issue

# 3. 常见的新手任务类型
- 文档改进
- 单元测试补充
- 代码注释优化
- 简单的 Bug 修复

📋 代码规范要求

提交前检查清单

# ✅ 代码格式检查
mvn checkstyle:check

# ✅ 单元测试
mvn test

# ✅ 许可证检查
mvn apache-rat:check

# ✅ 代码编译
mvn clean install -DskipTests

提交信息规范

# 格式: <type>(<scope>): <subject>

# 示例:
feat(plugin): 添加新的限流插件
fix(admin): 修复选择器删除时的空指针异常
docs(readme): 更新快速开始文档
test(divide): 补充 DividePlugin 的单元测试

第五部分:技术栈学习指引 🌐

1. 官方文档定位

📚 核心技术栈文档

技术 官方文档 重点章节
Spring Boot https://spring.io/projects/spring-boot Auto Configuration、Actuator
Spring WebFlux https://docs.spring.io/spring-framework/reference/web/webflux.html Reactive Core、WebClient
Project Reactor https://projectreactor.io/docs Mono/Flux、Operators
Netty https://netty.io/wiki/ User Guide、Best Practices
MyBatis https://mybatis.org/mybatis-3/ Dynamic SQL、Plugins
Apache Dubbo https://dubbo.apache.org/zh-cn/ 泛化调用、协议详解

📖 ShenYu 自身文档

必读章节(按优先级)

  1. Quick Start - 15分钟快速上手
  2. Plugin Center - 所有插件的使用说明
  3. Developer Guide - 自定义插件开发
  4. Deployment - 生产环境部署
  5. Design - 架构设计文档

文档地址


2. 学习路径建议

🎯 技能学习顺序

graph LR
    A[Java基础] --> B[Spring Boot]
    B --> C[Spring WebFlux]
    C --> D[Project Reactor]
    D --> E[ShenYu 架构]

    A --> F[设计模式]
    F --> E

    B --> G[微服务概念]
    G --> E

时间分配建议(总计 2-3 月):

  1. Java 17 新特性 - 1周
  2. Spring WebFlux + Reactor - 2-3周(重点难点)
  3. ShenYu 核心概念 - 1周
  4. ShenYu 源码阅读 - 4-6周
  5. 实战项目练习 - 2-4周

🔑 核心概念优先级

立即掌握(⭐⭐⭐⭐⭐)

  • Reactor 的 Mono/Flux
  • WebFlux 的异步处理模型
  • ShenYu 的 Selector & Rule
  • 插件链执行机制

逐步理解(⭐⭐⭐)

  • Netty 的 EventLoop
  • MyBatis 的动态 SQL
  • Disruptor 的无锁队列
  • 各种数据同步方式

可选进阶(⭐)

  • Dubbo 的底层通信
  • gRPC 的 Protobuf
  • Kubernetes Ingress
  • 分布式追踪

3. 工具与环境配置指南

🛠️ IDEA 推荐配置

# 1. 安装插件
- Lombok Plugin
- Maven Helper
- Rainbow Brackets
- GitToolBox

# 2. 代码风格导入
File -> Settings -> Editor -> Code Style -> Import Scheme
导入 script/shenyu_checkstyle.xml

# 3. 运行配置模板
Run -> Edit Configurations -> Templates -> Spring Boot
  Environment Variables: shenyu.local.enabled=true
  VM Options: -Xms512m -Xmx2048m

🐳 Docker 快捷命令

# 查看日志
docker logs -f shenyu-admin
docker logs -f shenyu-bootstrap

# 进入容器
docker exec -it shenyu-admin bash

# 重启容器
docker restart shenyu-admin

# 清理环境
docker-compose down -v
docker system prune -af

4. 进阶拓展方向

📰 技术博客推荐

ShenYu 官方博客

核心贡献者博客(搜索关键词):

  • "Apache ShenYu 架构解析"
  • "API 网关设计实践"
  • "Spring WebFlux 性能优化"

🎤 相关技术大会

  • ApacheCon - Apache 基金会年度大会
  • QCon - 软件架构与实践大会
  • ArchSummit - 全球架构师峰会

💬 社区与论坛

平台 链接 适用场景
GitHub Discussions https://github.com/apache/shenyu/discussions 英文讨论,官方响应快
Slack Apache Slack #shenyu 实时交流
邮件列表 dev@shenyu.apache.org 重要决策讨论
知乎/掘金 搜索"Apache ShenYu" 中文教程和经验分享

结语 🎓

恭喜你!如果你读到这里,说明你已经掌握了学习 Apache ShenYu 的完整路线图。

记住几个关键点:

  1. 先跑起来,再深入学习 - 不要一开始就啃源码
  2. 动手实践 > 阅读文档 - 自己写一个插件胜过看十篇文章
  3. 响应式编程是难点 - 多花时间理解 Reactor
  4. 参与社区 - 提问、回答、贡献代码,你会学得更快

最后,记得享受学习的过程!ShenYu 是一个设计精良的项目,你会从中学到很多架构设计的精髓。

有任何问题,随时在社区提问。Good luck! 🚀

目录
相关文章
|
1月前
|
Kubernetes Go API
Kubeflow-Model-Registry-架构学习指南
Kubeflow Model Registry 是一个用于管理机器学习模型元数据的基础设施,采用 Go、Python、React 和 Kubernetes 技术栈,支持模型版本、注册与存储追踪。本指南系统解析其分层架构、核心流程与代码结构,提供从环境搭建到贡献代码的完整学习路径,助力开发者深入掌握模型管理实践。
118 0
|
1月前
|
Kubernetes Go 调度
Kubeflow-Trainer-架构学习指南
本指南系统解析Kubeflow Trainer架构,涵盖核心设计、目录结构与代码逻辑,结合学习路径与实战建议,助你掌握这一Kubernetes原生机器学习训练平台的原理与应用。
387 139
|
1月前
|
Kubernetes API 开发工具
Kubeflow-Pipelines-架构学习指南
本指南带你深入 Kubeflow Pipelines 架构,从零掌握 ML 工作流编排。涵盖核心组件、代码结构、开发调试及贡献流程,结合实战练习与学习路径,助你由使用者进阶为贡献者。
341 139
|
1月前
|
Kubernetes Cloud Native Go
Kubeflow-KServe-架构学习指南
KServe是基于Kubernetes的生产级AI推理平台,支持多框架模型部署与管理。本指南从架构解析、代码结构到实战部署,系统讲解其核心组件如InferenceService、控制器模式及与Knative、Istio集成原理,并提供学习路径与贡献指南,助你快速掌握云原生AI服务技术。
393 139
|
25天前
|
存储 消息中间件 Kafka
Confluent 首席架构师万字剖析 Apache Fluss(二):核心架构
原文:https://jack-vanlightly.com/blog/2025/9/2/understanding-apache-fluss 作者:Jack Vanlightly 翻译:Wayne Wang@腾讯 译注:Jack Vanlightly 是一位专注于数据系统底层架构的知名技术博主,他的文章以篇幅长、细节丰富而闻名。目前 Jack 就职于 Confluent,担任首席技术架构师,因此这篇 Fluss 深度分析文章,具备一定的客观参考意义。译文拆成了三篇文章,本文是第二篇。
232 19
|
1月前
|
负载均衡 Java API
grpc-java 架构学习指南
本指南系统解析 grpc-java 架构,涵盖分层设计、核心流程与源码结构,结合实战路径与调试技巧,助你从入门到精通,掌握高性能 RPC 开发精髓。
175 7
|
1月前
|
人工智能 JavaScript 前端开发
GenSX (不一样的AI应用框架)架构学习指南
GenSX 是一个基于 TypeScript 的函数式 AI 工作流框架,以“函数组合替代图编排”为核心理念。它通过纯函数组件、自动追踪与断点恢复等特性,让开发者用自然代码构建可追溯、易测试的 LLM 应用。支持多模型集成与插件化扩展,兼具灵活性与工程化优势。
166 6

推荐镜像

更多