SpringCloud 微服务架构实战:Nacos + Gateway + Feign 全链路拆解(含单体双模式)

📅 2026/7/16 11:06:20 👁️ 阅读次数 📝 编程学习
SpringCloud 微服务架构实战:Nacos + Gateway + Feign 全链路拆解(含单体双模式)

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 bootyudao-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 支持一下!