【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 框架层:15 个 Starter 到底在干什么?

大家好,我是你们的源码拆解搭子。今天开始一个全新的系列------RuoYi-Vue-Pro 源码深度拆解

这个系列不是简单的"代码翻译",而是从产品经理 + 技术分析师的双重视角,一个模块一个模块地把这个项目扒干净。每个模块我都会回答五个问题:用了什么技术?为什么这样选?最初的需求是什么?竞品怎么做的?还能怎么改?

废话不多说,我们直接从整个项目的"地基"------yudao-framework 框架层开始。


一、先说结论:框架层到底在干什么?

一句话概括:yudao-framework 就是 RuoYi-Vue-Pro 的"水电管网",它不直接面向终端用户,但所有业务模块都跑在它上面。

具体来说,它以 15 个 Spring Boot Starter 的形式,为上层提供了这些通用能力:

Starter 干什么的 一句话解释
yudao-common 公共基础 统一返回格式、错误码、分页、基础实体类
yudao-spring-boot-starter-web Web 框架 统一异常处理、JSON 配置、Swagger 文档
yudao-spring-boot-starter-security 认证鉴权 Token 校验、权限过滤、安全上下文
yudao-spring-boot-starter-mybatis ORM 框架 MyBatis Plus 配置、分页插件、多数据源
yudao-spring-boot-starter-redis 缓存 Redis 配置、Spring Cache 集成
yudao-spring-boot-starter-biz-tenant 多租户 SQL 自动注入 tenant_id
yudao-spring-boot-starter-biz-data-permission 数据权限 SQL 自动追加部门/个人过滤条件
yudao-spring-boot-starter-biz-ip IP 地域 登录日志的 IP 定位
yudao-spring-boot-starter-job 定时任务 Quartz / XxlJob 集成
yudao-spring-boot-starter-mq 消息队列 RabbitMQ / Kafka / RocketMQ 适配
yudao-spring-boot-starter-excel Excel EasyExcel 封装,导入导出
yudao-spring-boot-starter-monitor 监控 Actuator + SkyWalking 链路追踪
yudao-spring-boot-starter-protection 限流保护 限流、幂等、分布式锁、idempotent
yudao-spring-boot-starter-websocket WebSocket 消息推送
yudao-spring-boot-starter-test 单元测试 测试基础设施

划重点!!! 一个新入职的 Java 开发者拿到这个项目后,不需要关心"怎么做分页""怎么做权限校验""怎么做多租户隔离"------框架全部自动处理了,他只需要写 Controller → Service → Mapper 的业务逻辑。

这个模块的产品定位类似于"操作系统"------用户不直接使用它,但所有应用都跑在它上面。


二、技术选型分析:为什么用这些技术,而不是别的?

2.1 ORM 层:为什么选 MyBatis Plus 而不是 JPA?

选择:MyBatis Plus 3.5.16 + MyBatis Plus Join 1.5.7

替代方案:JPA/Hibernate、jOOQ、原生 MyBatis

先上一组数据:在中国 Java 生态中,MyBatis 系列长期占据 ORM 使用率第一(据 2023 年 Java 开发者调查,MyBatis 系占比超 60%,JPA 约 20%)。为什么?

第一,SQL 可控性。 中国企业的业务场景复杂------多表关联查询、动态条件、存储过程,MyBatis 允许直接写 SQL,而 JPA 的 Criteria API 学习曲线陡峭、复杂查询表达力弱。对于外包和快速交付场景,团队更倾向于"能直接看到 SQL"。

第二,团队技术栈惯性。 中国大量 Java 开发者从 SSM(Spring + SpringMVC + MyBatis)时代过来,MyBatis 是默认技能树。选 JPA 会增加团队上手成本。

第三,MyBatis Plus 的增强恰到好处。 原生 MyBatis 需要手写大量 XML,MyBatis Plus 在保留 SQL 可控性的同时,提供了通用 CRUD、分页插件、条件构造器、代码生成等能力,是"半自动"和"全自动"之间的平衡点。

踩坑提醒:如果你是从 JPA 转过来的开发者,刚开始可能会觉得 MyBatis Plus 的 LambdaQueryWrapper 不够优雅。但用习惯了你会发现,它在复杂查询场景下的表达力远超 JPA。

竞品对比:JeecgBoot 也选了 MyBatis Plus;Pig 选了 MyBatis Plus;Guns 选了 MyBatis Plus。这几乎成了中国开源后台项目的"事实标准"。JPA 在海外更流行(如 JHipster),但在中国企业市场明显水土不服。

2.2 认证方案:为什么自研 Token 而不用 Spring Authorization Server?

选择:基于 Spring Security + 自研 Token 体系(system_oauth2_access_token 表 + Redis 缓存)

替代方案:Spring Authorization Server(SAS)、Keycloak、Auth0、Okta

RuoYi 的认证方案很有意思------它借用了 OAuth2 的概念(access_token、refresh_token、client、scope),但实现是高度简化的自研版本。Token 就是一个 UUID 字符串,存在 MySQL + Redis 里,没有 JWT,没有签名验证,没有标准的 Authorization Code Flow。

为什么这样设计?因为目标用户不需要完整的 OAuth2 。RuoYi 的核心场景是"企业内部后台管理系统",认证需求是:账号密码登录 → 拿 Token → 每次请求带 Token → Token 过期刷新。最多再加一个社交登录(微信/钉钉)。这是一个单系统、单组织的场景,不需要跨系统授权、不需要第三方应用接入。

如果用 Spring Authorization Server,配置复杂度会翻倍,使用者需要理解 OAuth2 的完整协议栈(grant type、scope 协商、token endpoint、introspection 等),对初级开发者极不友好。

注意:但这也是一个值得商榷的决策。如果企业未来需要对接其他系统(SSO 单点登录、开放平台),自研方案就需要大量改造。RuoYi 在微服务版本(yudao-cloud)中做了 SSO 支持,但单体版和微服务版在认证层的分裂会增加维护成本。

竞品对比:JeecgBoot 用了 JWT(Shiro + JWT);RuoYi-Cloud 用了 Spring Security OAuth2;Pig 用了 Spring Authorization Server(最标准);Guns 用了 JWT。RuoYi 的选择是"够用就好"的务实路线。

2.3 多租户方案:为什么选共享库 + 行级隔离?

选择:所有租户共用一个数据库,通过 tenant_id 列隔离(TenantDatabaseInterceptor 自动在 SQL 中注入 WHERE tenant_id = ?)

替代方案:每租户独立数据库、每租户独立 Schema、独立服务实例

多租户 SaaS 有三种经典架构,先上表格:

方案 隔离性 运维成本 适用场景
独立数据库 最强 最高 大客户、金融、政务
独立 Schema 中等规模 SaaS
共享库 + 行级隔离 最弱 最低 中小客户、成本敏感

RuoYi 选了第三种,因为它的目标用户是中小团队和外包公司。这些用户的 SaaS 产品可能有几十到几百个租户,每个租户数据量不大。共享库方案的优势是:部署简单(一个 MySQL 就够)、运维成本低、不需要动态创建数据库。

技术上,RuoYi 通过 MyBatis Plus 的 TenantLineHandler 拦截器在 SQL 解析层自动追加租户条件,开发者完全无感。这个设计非常巧妙------它利用了 JSqlParser 库在 AST 层面改写 SQL,比在代码层手动拼 WHERE 条件更安全。

踩坑提醒:行级隔离有一个根本性风险------如果代码 bug 导致 tenant_id 过滤失效,就会发生数据泄露。RuoYi 的缓解措施是:拦截器对未知表(不在 MyBatis Plus 元数据中的表)默认跳过------宁可不过滤也不误过滤。

竞品对比:JeecgBoot 也是共享库 + 行级隔离;Salesforce 用的是独立 Schema(因为客户体量大);有赞的 SaaS 方案提供了行级和库级两种模式可选。

2.4 连接池:Druid vs. HikariCP

选择:Alibaba Druid 1.2.28

替代方案:HikariCP(Spring Boot 默认)、Tomcat JDBC Pool

老规矩,先说结论:选 Druid 不是因为性能,而是因为监控 。Druid 不仅是一个连接池,更是一个数据库监控平台。它内置了 Web 控制台,可以查看 SQL 执行统计、慢 SQL 排行、连接池状态、Wall 防火墙(SQL 注入防护)。HikariCP 虽然性能更好(Spring Boot 默认),但缺乏可视化监控。对于需要运维能力的企业用户,Druid 是更实用的选择。

2.5 工具库:Hutool vs. Apache Commons

选择:Hutool 5.8.46

替代方案:Apache Commons(Lang3、Collections、IO 等)、Google Guava

Hutool 是"中国版 Guava",API 设计更贴合中国开发者习惯,覆盖范围极广(HTTP、加密、Excel、验证码、分词......),一个库替代了 Apache Commons 的多个子项目。对于快速开发场景,减少依赖数量就是减少版本冲突的风险。


三、需求溯源推演:最初的需求可能长什么样?

看到这里,你可能会有一个疑问:这个项目最初是怎么开始的?

如果穿越回这个项目启动前,产品经理面对的原始需求大概率是这样的:

"我们团队每年做 10 个以上的企业后台项目,每个项目都要花 2-3 周搭基础框架------登录、权限、用户管理、部门管理、字典、日志。能不能做一个通用的基础框架,新项目直接在上面开发,把基础框架的搭建时间从 3 周降到 0?"

这个需求的本质是降本增效------把重复劳动标准化。

然后产品经理会进一步拆解:

第一层需求:CRUD 代码生成。 "既然所有后台系统都是增删改查,那就做一个工具,选一张数据库表,自动生成前后端代码。" 这就是 yudao-module-infra 中 codegen 模块的起源。

第二层需求:权限模型标准化。 "每个项目都要做用户-角色-菜单的 RBAC 权限,能不能做成标准的?" 这就是 system_menu(1444 条预置菜单)、system_role、system_user_role、system_role_menu 这套模型的起源。

第三层需求:多租户。 "有些客户要做 SaaS,能不能默认支持多租户?" 这就是 tenant_id 列和 TenantDatabaseInterceptor 的起源。

第四层需求:可插拔。 "不是所有项目都需要工作流和商城,能不能按需启用?" 这就是 Maven 模块注释/取消注释的设计。

你会发现,整个框架的演进是一个"从自身痛点出发,逐步抽象"的过程。不是一开始就设计了 15 个 Starter,而是每做一个项目发现"这个能力上次也写过",就抽出来一个 Starter。


四、竞品对标分析:同类项目怎么做的?

话不多说,直接上表格:

维度 RuoYi-Vue-Pro(芋道) JeecgBoot Pig Guns SpringBlade
ORM MyBatis Plus MyBatis Plus MyBatis Plus MyBatis Plus MyBatis Plus
认证方案 自研 OAuth2 Token(UUID + Redis) Shiro + JWT Spring Authorization Server JWT JWT + Spring Security
多租户 共享库 + 行级拦截 共享库 + 手动过滤 共享库 + 行级拦截 无原生支持 共享库 + 行级拦截
代码生成 支持(Velocity 模板) 支持(Online 表单配置) 支持 支持(Guns 代码生成器) 支持(Blade 工具链)
数据权限 SQL 拦截器自动注入 注解 + AOP 注解 + AOP 注解 + AOP SQL 拦截器
数据库支持 10 种(含国产) 3-4 种 2-3 种 2-3 种 2-3 种
许可证 MIT(最宽松) Apache 2.0 Apache 2.0 Apache 2.0 Apache 2.0(部分商业)
业务模块丰富度 极高(CRM/ERP/Mall/AI/IoT/IM/MES/WMS) 中(主要做低代码) 低(专注认证授权)

RuoYi 的差异化优势

1. MIT 许可证。 这是最宽松的开源协议,商用无需保留版权声明。对于外包公司和企业用户,这是选型时的关键因素。JeecgBoot 和 Pig 都是 Apache 2.0,虽然也允许商用,但需要保留版权声明。

2. 业务模块覆盖面最广。 其他竞品主要聚焦在"基础框架 + 代码生成",RuoYi 是唯一一个把 CRM、ERP、商城、AI、IoT、MES 等业务系统全部开源的。这让它的定位从"脚手架"升级为"平台"。

3. 国产数据库适配最多。 10 种数据库(含达梦、人大金仓、瀚高、OpenGauss),直接命中政企"信创"需求。这在当前国产化替代的大背景下,是一个重要的竞争壁垒。

RuoYi 的潜在劣势

1. 认证方案不够标准。 自研 Token 体系在简单场景下够用,但如果企业需要 SSO 或开放平台,改造成本高。Pig 的 Spring Authorization Server 方案在标准化方面更胜一筹。

2. 单体架构的天花板。 所有模块打在一个 JAR 里,当业务模块越来越多(现在已经 13 个),启动时间和内存占用会成为问题。虽然 yudao-cloud 微服务版本存在,但维护两套代码的成本不低。

3. 框架层抽象过重。 15 个 Starter 对新用户来说认知负担不小。相比之下,JeecgBoot 的框架层更薄,上手更快。


五、核心请求处理流程

一个 API 请求从进入 RuoYi 到返回响应,要经过框架层的完整处理链路。我画了一个流程图,建议收藏:

复制代码
客户端请求
    │
    ▼
┌─────────────────────────────────┐
│  TenantContextWebFilter         │  ① 从 Header 提取 tenant-id
│  提取租户上下文                  │     存入 ThreadLocal(TransmittableThreadLocal)
└─────────────┬───────────────────┘
              │
              ▼
┌─────────────────────────────────┐
│  TokenAuthenticationFilter      │  ② 从 Header 提取 access_token
│  Token 认证过滤器                │     调 OAuth2TokenCommonApi.checkAccessToken()
│                                 │     校验通过 → 构建 LoginUser 放入 SecurityContext
│                                 │     校验失败 → 返回 401 JSON
└─────────────┬───────────────────┘
              │
              ▼
┌─────────────────────────────────┐
│  ApiAccessLogFilter             │  ③ 记录请求 URL、参数、响应、耗时
│  API 访问日志                   │     自动脱敏(password/token 等字段不记录)
└─────────────┬───────────────────┘
              │
              ▼
┌─────────────────────────────────┐
│  @PreAuthorize("@ss.has...")    │  ④ 方法级权限校验
│  Spring Security 权限校验        │     调 PermissionCommonApi.hasAnyPermissions()
│                                 │     走 Redis 缓存 → 查角色-菜单映射
└─────────────┬───────────────────┘
              │
              ▼
┌─────────────────────────────────┐
│  @DataPermission                │  ⑤ 行级数据权限
│  MyBatis SQL 拦截器             │     根据角色 data_scope 自动追加 WHERE 条件
│                                 │     ALL/DEPT_CUSTOM/DEPT_ONLY/DEPT_AND_CHILD/SELF
└─────────────┬───────────────────┘
              │
              ▼
┌─────────────────────────────────┐
│  TenantDatabaseInterceptor      │  ⑥ 多租户 SQL 拦截
│  自动追加 WHERE tenant_id = ?   │     对继承 TenantBaseDO 的所有表生效
└─────────────┬───────────────────┘
              │
              ▼
┌─────────────────────────────────┐
│  Controller → Service → Mapper  │  ⑦ 业务逻辑执行
│  BaseMapperX 提供便捷方法        │     DefaultDBFieldHandler 自动填充审计字段
└─────────────┬───────────────────┘
              │
              ▼
┌─────────────────────────────────┐
│  CommonResult<T>                │  ⑧ 统一响应格式
│  { code: 0, msg: "", data: {} } │     异常由 GlobalExceptionHandler 统一处理
└─────────────────────────────────┘

划重点!!! 这 8 步链路中,①②③④⑤⑥ 都是框架自动完成的,开发者只需要关心第 ⑦ 步。这就是框架的价值------把 80% 的通用逻辑固化下来,让开发者只写 20% 的业务差异


六、数据模型解读:框架层的关键"表"

框架层本身不直接建表(表都在 system 和 infra 模块),但它定义了几个关键的数据模型约定,这里必须搞清楚:

BaseDO(基础实体):所有数据库实体都继承它,自动拥有 5 个审计字段------createTime、updateTime、creator、updater、deleted。这意味着系统里每一条数据都知道"谁创建的、什么时候创建的、谁最后改的、是否已删除"。

TenantBaseDO(租户实体):继承 BaseDO,额外增加 tenantId 字段。需要多租户隔离的表都继承它,框架自动追加租户过滤。

CommonResult(统一返回):所有 API 返回 { code, msg, data } 三段式。code=0 表示成功,非零表示失败。这个设计让前端可以用统一逻辑处理所有接口响应。

ErrorCode(错误码体系):全局错误码 0-999,业务错误码从 10 亿开始。每个模块有自己的错误码段,互不冲突。代码注释里写着"设计成对象是为了未来做 i18n 国际化"------这是一个面向未来的设计预留。

跨模块 API 接口(*CommonApi) :这是一个精妙的架构设计。接口定义在 yudao-common 中(如 OAuth2TokenCommonApi、PermissionCommonApi),实现分散在各业务模块中。这样框架层可以调用业务层的能力,而不需要直接依赖业务模块------依赖倒置原则的经典应用。


七、产品设计亮点与槽点

亮点

1. 依赖倒置的跨模块通信设计。 把 API 接口放在 common 包里,实现放在业务模块里。这让框架层(security starter)可以调用系统模块的能力(校验 Token),而不需要 framework 依赖 system------避免了循环依赖。这个设计在同类开源项目中不常见,大多数用的是事件驱动或直接依赖。

2. 数据权限的 SQL 拦截实现。 通过 DataPermissionRuleHandler 在 SQL AST 层面自动注入 WHERE 条件,开发者只需要加一个 @DataPermission 注解。这比在代码层手动拼条件安全得多------不会因为某个开发者忘了加条件而泄露数据。代码中还详细记录了"用户调部门后历史数据可见性"的三种解决方案和最终选择,体现了工程决策的严谨性。

3. 全局异常处理中的"表不存在"智能检测。 GlobalExceptionHandler.handleTableNotExists() 能识别出是因为某个业务模块未启用(如 bpm、crm、ai)导致的表不存在错误,并返回友好的提示信息(含文档链接)。这大大降低了用户部署时的困惑------"为什么报错"变成了"哦,我需要启用这个模块"。

4. Mock 登录机制。 开发环境下可以通过 {mockSecret}{userId} 格式的 Token 模拟任意用户登录,方便调试。代码注释中特意强调"线上环境一定要关闭"。这是一个非常接地气的开发者体验设计。

槽点

1. Starter 数量过多,认知负担重。 15 个 Starter 对新用户来说是一个"命名空间爆炸"。虽然每个 Starter 职责清晰,但"biz-tenant"和"biz-data-permission"带了 biz 前缀,其他没有,分类标准不够直观。如果能把 Starter 分成"基础层"和"业务层"两组,并在文档中明确说明,会降低理解成本。

2. Token 方案缺乏向前兼容性。 自研的 UUID Token 方案在需要 SSO 或开放平台时会成为瓶颈。如果未来要支持"第三方应用通过 OAuth2 接入",需要大量改造。建议在 README 中明确说明这个方案的适用边界,并给出升级路径。

3. 错误码的 i18n 预留尚未实现。 ErrorCode 设计成对象是为了"未来做国际化",但目前 msg 字段是硬编码的中文字符串。如果真的有国际化需求,改造成本不低。


八、发散性思考

如果让我重新设计,我会怎么改?

1. 引入"能力开关"机制。 目前模块启用靠修改 pom.xml 注释,这对非 Java 背景的运维人员不友好。更好的方式是在 application.yml 中做能力开关(yudao.module.bpm.enabled=true),配合 @ConditionalOnProperty 注解自动加载/跳过模块配置。这样运维人员改一行配置就能启用模块,不需要重新编译。

2. 框架层提供"健康检查仪表盘"。 类似 Spring Boot Admin 但更面向业务------展示每个模块的启用状态、数据库连接状态、Redis 命中率、Token 过期统计、租户数量等。让运维人员有一个统一的健康检查入口。

3. 数据权限支持"自定义规则"。 目前数据权限只支持"按部门"维度。但实际业务中还有"按项目""按区域""按客户等级"等维度。如果能让管理员在页面上配置数据权限规则,会更灵活。

这套设计思路可以迁移到哪里?

1. 任何需要"多套系统合一"的场景。 比如一个 SaaS 公司收购了另一个 SaaS 公司,需要把两套系统合并------多租户 + 行级隔离的方案可以直接复用。

2. 中台战略。 框架层的 Starter 模式本质上就是"能力中台"------把通用能力下沉到基础设施层,业务团队按需调用。这个思路可以推广到任何需要"复用"的组织。

3. 低代码/无代码平台。 框架层 + 代码生成器的组合,已经是一个"半低代码"方案了。如果进一步抽象------让用户在页面上配置数据模型、自动生成 CRUD 页面------就是一个完整的低代码平台。JeecgBoot 的 Online 表单就是这个方向。


九、关键代码导读(最值得读的 5 个文件)

话不多说,直接上干货:

文件 路径 为什么值得读
CommonResult.java yudao-common/.../pojo/CommonResult.java 理解整个系统的 API 契约。只有 50 行代码,但 error(CommonResult<?>) 方法背后的泛型转换逻辑值得细品------它解决的是"跨模块调用时错误传播"的架构问题。
TokenAuthenticationFilter.java yudao-starter-security/.../filter/TokenAuthenticationFilter.java 理解认证链路的核心。每个请求怎么被认证?Token 从哪来?校验失败怎么处理?Mock 登录怎么实现?全在这 100 多行代码里。
TenantDatabaseInterceptor.java yudao-starter-biz-tenant/.../db/TenantDatabaseInterceptor.java 理解多租户隔离的核心。它展示了如何在 SQL AST 层面自动注入条件------这是"框架替你做事"的典型实现。读完你会理解"为什么加了 tenant_id 列就能自动隔离"。
DeptDataPermissionRule.java yudao-starter-biz-data-permission/.../rule/dept/DeptDataPermissionRule.java 理解数据权限的实现。代码中有大段中文注释解释了"用户调部门后历史数据可见性"的三种方案和最终选择------这是一份活的设计文档。
GlobalExceptionHandler.java yudao-starter-web/.../handler/GlobalExceptionHandler.java 理解系统的"容错设计"。12+ 种异常类型如何映射到友好的错误响应?"表不存在"的智能检测怎么做的?敏感信息脱敏怎么实现的?全在这里。

十、写在最后

框架层是 RuoYi-Vue-Pro 最"安静"但最重要的部分。它不产出任何用户可见的功能,但决定了整个系统的开发效率、安全性和可维护性。

作为产品经理,从框架层学到的最重要的一个思维模型是:识别重复模式,将其标准化为基础设施。 这不是一个技术决策,而是一个产品决策------它回答的是"我们到底在卖什么"的问题。RuoYi 卖的不是某个具体功能,而是"不再重复造轮子"的效率承诺。

相关推荐
「QT(C++)开发工程师」10 小时前
AI Agent 核心组件
人工智能·ai·aigc·ai编程·ai写作
右耳朵猫AI10 小时前
Claude Code 智能体循环入门
ai编程·claude code
程序员黑豆10 小时前
从零开始:编写第一个鸿蒙(HarmonyOS)程序
前端·harmonyos
lastknight11 小时前
CSS @layer
前端·css
李宸净11 小时前
Web自动化测试selenium+python
前端·python·selenium
淡海水11 小时前
06-04-YooAsset源码-Unity加密解密服务
前端·unity·性能优化·c#·游戏引擎·yooasset
trigger33312 小时前
desk-health-web-community-post
前端
倒流时光三十年12 小时前
Logback 系列(7):常用 Appender(控制台 / 文件 / 滚动文件)
java·前端·logback