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 连接 + 灰度 metadataspring:cloud:nacos:server-addr:127.0.0.1:8848discovery:namespace:devmetadata:version:1.0.0# 灰度发布用的版本标config:namespace:devgroup: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-apiuri:grayLb://system-server# 自定义灰度负载均衡协议predicates:-Path=/admin-api/system/**# 统一前缀路由-id:crm-admin-apiuri:grayLb://crm-serverpredicates:-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;// 降级:无匹配版本则用全部实例,保证可用}returnNacosBalancer.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"publicinterfaceAdminUserApi{@GetMapping(ApiConstants.PREFIX+"/get")// PREFIX = /rpc-api/system/userCommonResult<AdminUserRespDTO>getUser(@RequestParam("id")Longid);}关键是上下文透传——服务间调用时,用 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 支持一下!