SpringCloud 微服务架构实战:Nacos + Gateway + Feign 全链路拆解(含单体双模式)
🌐 演示地址:http://ruoyioffice.com | 📦 源码1·GitHub:ruoyi-office | 📦 源码2·GitCode:ruoyi-office | 📦 源码3·Gitee:ruoyi-office | 💬 微信:17156169080(备注「RuoYi Office」)
"微服务"这三个字,听着高大上,落地却处处是坑:服务怎么注册、配置怎么集中管、网关怎么路由、服务间怎么调用、登录态和租户信息怎么透传……更现实的是,很多中小团队其实并不需要一上来就拆微服务。本文基于 RuoYi Office 真实源码(Spring Boot 3.5 + Spring Cloud 2025 + Spring Cloud Alibaba),拆解一套 Nacos + Gateway + Feign 的微服务全链路,并讲清它最妙的设计——一套代码,单体和微服务两种模式自由切换。

*▲ 微服务全景:客户端 → Gateway(统一入口/grayLb 灰度)→ 各 -server 服务(注册 Nacos);服务间走 Feign /rpc-api 直连;配置走 Nacos 配置中心,路由可热刷新
引言:微服务到底难在哪?
微服务的复杂度,是从"一个进程"变成"一堆进程要协同"开始的。 几个绕不开的痛点:
痛点一:服务发现。服务实例动态上下线,调用方怎么知道对方在哪?
痛点二:配置散乱。十几个服务各有一套配置文件,改个数据库地址要改十几处。
痛点三:统一入口。客户端不可能记住每个服务的地址,需要一个网关统一对外。
痛点四:上下文透传。登录用户、租户 ID 在服务间调用时怎么传下去?
痛点五:要不要拆。很多团队盲目上微服务,结果运维成本暴涨、收益寥寥。
| 硬编码服务地址 | 实例变更就崩 |
| 配置分散 | 改一处要改十几遍 |
| 无统一网关 | 客户端要记一堆地址 |
| 上下文丢失 | 服务间调用丢登录态 |
方案一句话:Nacos 管注册和配置,Gateway 管入口和路由,Feign 管内部调用并透传上下文,且支持单体/微服务双模式。
一、最妙的设计:一套代码,双模式切换
这套架构最务实的地方是:同一份代码,靠 Maven Profile 切换单体或微服务。 中小团队先用单体省运维,做大了再切微服务,零重构:
| 单体 | mvn -P boot | yudao-server 一个进程聚合所有模块 | 中小团队、起步期 |
| 微服务 | mvn -P cloud(默认) | Gateway + N 个 *-server 独立部署 | 规模化、需独立扩缩容 |
<!– pom.xml:Profile 控制各子模块是否独立打 fat jar –>
<profile>
<id>boot</id>
<properties><skip.repackage>true</skip.repackage></properties> <!– 子模块不单独打包,由 yudao-server 聚合 –>
</profile>
<profile>
<id>cloud</id>
<activation><activeByDefault>true</activeByDefault></activation>
<properties><skip.repackage>false</skip.repackage></properties> <!– 各 *-server 独立 fat jar –>
</profile>
这是真正解决"要不要上微服务"焦虑的答案:不用提前选边站,单体起步、平滑演进。 详见专文《单体还是微服务?中小企业的务实选择》。
二、Nacos:注册中心 + 配置中心二合一
Nacos 一个组件同时承担"服务发现"和"配置集中管理"。 各服务通过 config.import 同时加载本地 profile 配置和 Nacos 配置:
# 各 *-server 的 application.yaml:服务名 + 配置双源导入
spring:
application:
name: system–server # 必须与网关路由 uri、Feign @FeignClient name 一致
config:
import:
– optional:classpath:application–${spring.profiles.active}.yaml # 本地 profile
– optional:nacos:${spring.application.name}–${spring.profiles.active}.yaml # Nacos 配置
# application-dev.yaml:Nacos 连接 + 灰度 metadata
spring:
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: dev
metadata:
version: 1.0.0 # 灰度发布用的版本标
config:
namespace: dev
group: DEFAULT_GROUP
设计要点:服务注册无需 @EnableDiscoveryClient(Spring Cloud 2020+ 引入 starter 即自动注册);配置放 Nacos 后,连网关路由都能在 Nacos 里热改、热刷新。
三、Gateway:统一入口 + grayLb 灰度路由
网关用显式静态路由(不是 discovery.locator 自动发现),URI 用自定义的 grayLb:// 协议做灰度负载均衡。 这样路由可控、可灰度:
# 网关路由:每个模块一条,grayLb 走灰度负载均衡
spring:
cloud:
gateway:
server:
webflux:
routes:
– id: system–admin–api
uri: grayLb://system–server # 自定义灰度负载均衡协议
predicates:
– Path=/admin–api/system/** # 统一前缀路由
– id: crm–admin–api
uri: grayLb://crm–server
predicates:
– Path=/admin–api/crm/**
灰度负载均衡按请求头 version 匹配 Nacos 实例的 metadata.version,实现金丝雀发布:
// GrayLoadBalancer:优先选 version 匹配的实例,无匹配则回退全部实例
List<ServiceInstance> chosen = instances.stream()
.filter(i -> Objects.equals(version, i.getMetadata().get("version")))
.collect(Collectors.toList());
if (CollUtil.isEmpty(chosen)) {
chosen = instances; // 降级:无匹配版本则用全部实例,保证可用
}
return NacosBalancer.getHostByRandomWeight3(chosen); // 按 Nacos 权重随机
外部 API 统一走 /admin-api/{module}/** 前缀,对外只暴露网关一个入口(端口 48080)。 
▲ 基础设施·Java 监控(Spring Boot Admin):实时查看各微服务实例的健康、JVM、线程、日志,是微服务运维的"仪表盘"

▲ 基础设施·API 访问日志:各微服务(system/crm/erp…)的请求经网关统一转发,路径、耗时、结果码全留痕,可按服务/路由排查链路
四、Feign:服务间调用走 /rpc-api 直连
对外 API 走 /admin-api 经网关,服务间内部调用走 /rpc-api 经 Feign 直连(不经网关),路径分离、职责清晰。 接口定义在 *-api 模块:
// AdminUserApi(在 yudao-module-system-api):name 指向目标服务名
@FeignClient(name = ApiConstants.NAME) // ApiConstants.NAME = "system-server"
public interface AdminUserApi {
@GetMapping(ApiConstants.PREFIX + "/get") // PREFIX = /rpc-api/system/user
CommonResult<AdminUserRespDTO> getUser(@RequestParam("id") Long id);
}
关键是上下文透传——服务间调用时,用 Feign 拦截器把登录用户和租户 ID 带过去,下游才知道"现在是谁、哪个租户在调用":
// 框架内置 Feign 请求拦截器,自动透传上下文
LoginUserRequestInterceptor // 透传 login-user 头(当前登录用户)
TenantRequestInterceptor // 透传 tenant-id 头(当前租户)
DataPermissionRequestInterceptor // 透传数据权限上下文
| /admin-api/{module} | 对外管理端 API | ✅ 经 Gateway |
| /app-api/{module} | 对外 App API | ✅ 经 Gateway |
| /rpc-api/{module} | 服务间内部 RPC | ❌ Feign 直连 |
诚实提示:当前 Feign 客户端未实现 fallback 降级(源码留有 TODO)。生产对可用性要求高时,建议补充 fallbackFactory 或引入熔断组件。
五、技术亮点总结
| 双模式 | Maven Profile boot/cloud | 单体起步、平滑演进 |
| 注册+配置 | Nacos 二合一 | 服务发现 + 配置集中 |
| 配置双源 | classpath + Nacos import | 本地 + 远端热刷新 |
| 统一入口 | Gateway 静态路由 | 对外只暴露一个入口 |
| 灰度发布 | grayLb + version metadata | 金丝雀按版本路由 |
| 上下文透传 | Feign 拦截器 | 服务间不丢登录/租户 |
六、快速体验
- 在线演示:http://ruoyioffice.com/web/(账号 admin / admin123)
- 操作路径:基础设施 → 监控中心 → Java 监控 / API 接口文档
- 推荐体验流程:看 Java 监控里的服务实例 → 翻 API 接口聚合文档 → 对比 -P boot/-P cloud 启动
| 后端 | GitHub · GitCode · Gitee |
| 前端 | GitCode |
延伸阅读:Spring Cloud Gateway 网关设计 · 单体还是微服务?务实选择 · 多租户 SaaS 架构。
常见问题(FAQ)
RuoYi Office 用的是什么微服务技术栈?
Spring Boot 3.5 + Spring Cloud 2025 + Spring Cloud Alibaba,Nacos 做注册中心和配置中心,Spring Cloud Gateway 做网关,OpenFeign 做服务间调用,Java 17。
一定要拆微服务吗?
不一定。这套架构支持一套代码双模式:mvn -P boot 打单体(一个进程聚合所有模块),mvn -P cloud 打微服务。中小团队可先用单体省运维,做大后再平滑切微服务,无需重构。
网关路由是自动发现的吗?
不是。采用显式静态路由表(在 yaml 或 Nacos 配置),URI 用自定义 grayLb:// 协议做灰度负载均衡,路由可控、可在 Nacos 热刷新,而非 discovery.locator 自动生成。
服务间调用怎么传登录用户和租户?
通过 Feign 请求拦截器自动透传:LoginUserRequestInterceptor 传 login-user 头、TenantRequestInterceptor 传 tenant-id 头、DataPermissionRequestInterceptor 传数据权限上下文。
对外和内部接口怎么区分?
对外管理端走 /admin-api/{module}(经网关),对外 App 走 /app-api/{module},服务间内部 RPC 走 /rpc-api/{module}(Feign 直连,不经网关),路径前缀分离。
💡 想要体验 RuoYi Office 的强大功能?
🌐 在线演示:http://ruoyioffice.com/web/(账号 admin / admin123)
📦 源码仓库:GitHub | GitCode | Gitee
💬 技术咨询:添加微信 17156169080,备注「RuoYi Office」
⭐ 如果觉得不错,请给个 Star 支持一下!




