技术架构
功能分层见 开发指南。本篇说明进程如何部署:同一套后端源码可以运行在一个进程(单体),或拆成网关 + 多个服务(微服务)。对外端口都是 48080,前缀仍是 /admin-api、/app-api。日常开发使用单体。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 单体 | 只启动一个 yudao-server,所有业务模块在同一个进程里 | 编译或 IDEA 运行时选 boot |
| 微服务 | 先启动网关,再启动各个 *-server | 编译或 IDEA 运行时选 cloud(默认选项) |
yudao-server | 单体部署时的后端进程 | ruoyi-office/yudao-server/ |
yudao-gateway | 微服务入口,端口 48080 | ruoyi-office/yudao-gateway/ |
| Nacos | 微服务的注册中心与配置中心;单体默认关闭 | yudao-server 的 application.yaml |
示意图:同一套模块,两种部署方式。浏览器只访问 48080。
两种形态的联系
对照两张图时,先看两边对齐的部分。这些不随单体或微服务改变。
| 层 | 两种形态相同 |
|---|---|
| 前端 | 电脑 / 手机 → 管理后台 Vben、管理后台 UniApp、用户前端 UniApp |
| 接入 | Nginx 反代 HTTP |
| 存储 | MySQL、Redis、OSS / MinIO;需要搜索时再接入 Elasticsearch |
| 中间件 | XXL-Job 调度、RocketMQ 收发 |
| 运维 / 监控 | Jenkins、Docker、Portainer、SBA、Druid、SkyWalking |
模块源码也是同一份:yudao-module-*-api + *-server。变化的是进程数量,以及模块之间如何调用。
单体技术架构
本机开发与小规模交付采用单体。Nginx 将请求反向代理到同一个 yudao-server :48080。system / infra / 业务模块运行在同一进程,模块间调用走本地 ApiImpl,不必先启动 Nacos。

单体:后端集中在同一进程。上方为 XXL-Job、RocketMQ、Redisson。
yudao-server 是空壳:pom.xml 声明要装哪些 yudao-module-xxx-server,启动类扫 cn.iocoder.yudao.module。裁模块改依赖,不是改扫描包。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 启动类 | YudaoServerApplication | ruoyi-office/yudao-server/.../YudaoServerApplication.java |
| 端口 / 应用名 | 48080 / yudao-server | application-local.yaml、application.yaml |
| Nacos | discovery / config 都是 enabled: false | 同文件 spring.cloud.nacos |
| OpenFeign | 依赖里排除,模块间走本地 Bean | yudao-server/pom.xml 对 yudao-spring-boot-starter-rpc 的 exclusion |
| 锁 | Redisson,图上「获取锁」 | yudao-spring-boot-starter-protection / Redis |
本机以单体方式启动:在 IDEA 的 Maven 面板勾选 boot(不要使用默认的 cloud),再运行 YudaoServerApplication。命令行等价于:
cd ruoyi-office
mvn -P boot -DskipTests compile前端代理仍指向 http://127.0.0.1:48080/admin-api。
工具默认按微服务打包
IDEA / Maven 如果没改成 boot,会按微服务方式打各个模块,端口对不上单体。
微服务技术架构
需要按服务独立扩容时采用微服务。Nginx 将请求负载均衡到 Gateway,Gateway 再按路径转发到 system-server / infra-server / 业务 *-server。

微服务:中间多一列 Gateway,业务按进程拆开。
图上方的 Seata、Nacos、Sentinel 是可接拓扑。本仓库默认:微服务才用 Nacos;没有成套 Seata / Sentinel。跨库一致性自己收口(本地消息、幂等、对账)。限流、幂等、锁在 yudao-spring-boot-starter-protection。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 网关 | GatewayServerApplication,gateway-server,:48080 | ruoyi-office/yudao-gateway/ |
| system | system-server,:48081 | yudao-module-system/yudao-module-system-server/ |
| infra | infra-server,:48082 | yudao-module-infra/yudao-module-infra-server/ |
| bpm | bpm-server,:48083 | yudao-module-bpm/yudao-module-bpm-server/ |
| oa | oa-server,:48106 | yudao-module-oa/yudao-module-oa-server/ |
| 其它模块 | 各自 server.port | 对应 yudao-module-*-server |
进程名必须等于 spring.application.name,也必须等于 *-api 里 @FeignClient 的 name。Nacos 本机默认 127.0.0.1:8848,命名空间 dev:
spring:
config:
import:
- optional:classpath:application-${spring.profiles.active}.yaml
- optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml缺 Nacos 时本地 yaml 仍能启动,注册、发现、动态路由会空。
差异与决策
| 看什么 | 单体 | 微服务 |
|---|---|---|
| 进程 | 一个 yudao-server :48080 | Gateway :48080 + 各 *-server |
| 模块间调用 | 同 JVM,本地 ApiImpl | Feign,注册名 = spring.application.name |
| 注册 / 配置 | 关闭 Nacos | Nacos |
| 额外组件 | Redisson 分布式锁 | Gateway;Seata / Sentinel 为可选项 |
| 定时任务 | 一个执行器 | 各进程自己的 xxl.job.executor.appname |
本机开发接口、联调单据、调试定时任务:使用单体。需要按域扩容、多实例灰度、团队分别启动服务:使用微服务。本机开发不必同时启动全部 *ServerApplication。
请求如何进入
网关按路径将 /admin-api/{module}/**、/app-api/{module}/** 转发到对应服务。文档路径再 RewritePath 为服务根路径上的 /v3/api-docs。浏览器、App、/doc.html 均访问 48080。48081、48106 仅供进程监听和本机断点。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 路由表 | spring.cloud.gateway.server.webflux.routes | ruoyi-office/yudao-gateway/src/main/resources/application.yaml |
| 认证 | 有 Token 则调 system 校验,写入 login-user 头;没有 Token 也放行,登录校验仍在业务服务 | .../filter/security/TokenAuthenticationFilter.java |
| 访问日志 | 方法、路径、耗时、trace | .../filter/logging/AccessLogFilter.java |
| 跨域 | 全局 CORS | .../filter/cors/CorsFilter.java |
| 动态路由 | 改 Nacos 里 gateway-server.yaml | .../route/dynamic/package-info.java |
| 文档聚合 | Knife4j Gateway | 同 yaml 的 knife4j.gateway |
- id: system-admin-api
uri: grayLb://system-server
predicates:
- Path=/admin-api/system/**
filters:
- RewritePath=/admin-api/system/v3/api-docs, /v3/api-docs新加可独立部署的模块:给 *-server 配 spring.application.name 和端口,再在网关加 Path 和 Knife4j 分组。细节见 接口文档、新建服务。
网关校验 Token 用 WebClient + 负载均衡,不走 OpenFeign(WebFlux 下没有现成的 Reactive Feign)。Token 过期或校验失败时仍转发,由下游决定 401。
模块间如何调用
契约在 *-api,实现在 *-server。微服务通过 OpenFeign 按服务名调用;单体在同一进程内直接注入 *ApiImpl。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| RPC 前缀 | /rpc-api | yudao-framework/yudao-common/.../RpcConstants.java |
| 服务名 | 与 spring.application.name 一致,如 system-server | 例如 yudao-module-system-api/.../ApiConstants.java |
| 接口 | @FeignClient + @GetMapping(PREFIX + "/get"),返回 CommonResult<T> | 例如 AdminUserApi |
| 实现 | @RestController 实现同一接口 | 例如 AdminUserApiImpl |
| 放行 | 各模块 Security 对 ApiConstants.PREFIX + "/**" permitAll | 例如 system 的 SecurityConfiguration |
| 用户 / 租户透传 | Feign 带 login-user、租户号 | LoginUserRequestInterceptor、TenantRequestInterceptor |
| 可选模块 | 仅 Nacos 发现打开时才注册 Feign | 例如 OaAssetRpcConfiguration |
@FeignClient(name = ApiConstants.NAME, contextId = "adminUserApi")
public interface AdminUserApi {
String PREFIX = ApiConstants.PREFIX + "/user";
@GetMapping(PREFIX + "/get")
CommonResult<AdminUserRespDTO> getUser(@RequestParam("id") Long id);
}ApiConstants.NAME 是 system-server,PREFIX 是 /rpc-api/system。实现类:yudao-module-system-server/.../api/user/AdminUserApiImpl.java。消费者在自己的 RpcConfiguration 里 @EnableFeignClients(clients = {AdminUserApi.class, ...}),不要扫对方 *-server 的内部类。
定时任务在微服务里落在各自进程的执行器上,xxl.job.executor.appname 用 ${spring.application.name}。写法见 定时任务 XXL-Job。
本机联调
共享环境已有一套微服务时,本机只启动正在修改的服务,通过环境标签将请求转发到本机。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 标签 | yudao.env.tag,写入 Nacos 实例 metadata.tag | yudao-spring-boot-starter-env/.../EnvProperties.java |
| 请求头 | tag;值为 ${HOSTNAME} 时网关换成本机主机名 | yudao-gateway/.../util/EnvUtils.java |
| 灰度 URI | grayLb://system-server,不是 lb:// | 网关 application.yaml |
| 负载均衡 | 先按 version,再按 tag 滤实例 | .../filter/grey/GrayLoadBalancer.java |
| Feign 透传 | 调用下游时带上当前 tag | .../env/core/fegin/EnvRequestInterceptor.java |
顺序:Nacos 已起 → 启动 GatewayServerApplication(占 48080)→ 启动正在改的 *ServerApplication → 实例加上 yudao.env.tag → 浏览器或 Knife4j 带 tag。
没有 tag 时,网关优先选择同样不带 tag 的实例,避免把演示环境的请求转发到本机。标签不匹配时回退到全部实例,日志中会有警告。version 请求头对应实例 metadata.version(system 本地一般为 1.0.0)。
配置
没有「微服务」菜单。改打包方式后要重新启动,页面上没有这个开关。模块怎么拆、Admin / App 为什么分开,见 项目结构。
