若依多模块工程化设计
本文基于若依3.9.2、SpringBoot3版本。

若依多模块工程化设计
为什么用多模块
单体项目把所有代码塞在一个模块里,随着业务增长会遇到几个实际问题:改动一个工具类需要重新编译整个项目、不同团队互相踩代码、某些功能想单独拆出来用做不到。多模块设计把项目按职责拆分成独立的 Maven 子工程,每个模块有自己的 pom 文件和源码目录,带来三个直接好处:
- 职责隔离:每个模块只关注一件事(如安全、数据、工具),边界清晰
- 独立编译:修改 system 模块的业务代码,common 和 framework 无需重新构建
- 可裁剪:不需要的模块(如代码生成、定时任务)可以直接删除,不影响核心功能
若依正是这样做的——6 个模块各司其职,通过依赖关系组合成一个完整的应用。
模块总览
若依采用 Maven 多模块设计,共 6 个模块:
com.ruoyi(父POM)
├── ruoyi-common 公共基础层
├── ruoyi-system 系统业务层
├── ruoyi-framework 框架核心层
├── ruoyi-quartz 定时任务模块
├── ruoyi-generator 代码生成模块
└── ruoyi-admin 启动入口层
模块间的依赖关系:
┌──────────────┐
│ ruoyi-admin │ ← 最终启动入口
└──────┬───────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌────────────┐ ┌──────────┐ ┌──────────────┐
│ ruoyi- │ │ ruoyi- │ │ ruoyi- │
│ framework │ │ quartz │ │ generator │
└─────┬──────┘ └────┬─────┘ └──────┬───────┘
│ │ │
▼ ▼ ▼
┌────────────┐ ┌──────────┐ ┌──────────┐
│ ruoyi- │ │ ruoyi- │ │ ruoyi- │
│ system │ │ common │ │ common │
└─────┬──────┘ └──────────┘ └──────────┘
│
▼
┌──────────┐
│ ruoyi- │
│ common │ ← 最底层
└──────────┘
各模块职责与打包方式:
| 模块 | 职责 | 打包 |
|---|---|---|
| ruoyi-common | 统一返回对象、分页封装、自定义注解、常量、异常体系、工具类 | jar |
| ruoyi-system | 用户、角色、菜单、部门、字典等系统管理功能的 Entity/Mapper/Service | jar |
| ruoyi-framework | Spring Security 配置、AOP 切面、全局异常处理、异步任务管理 | jar |
| ruoyi-quartz | 基于 Quartz 的定时任务管理,支持 CRUD 与暂停恢复 | jar |
| ruoyi-generator | 基于 Velocity 模板引擎从数据库表生成前后端代码 | jar |
| ruoyi-admin | 启动类、Controller、配置文件,最终打包部署的模块 | jar/war |
Maven 的依赖传递机制下,admin 无需直接声明 common 的依赖,通过 framework → system → common 的传递链自动获得。
可裁剪设计
quartz 和 generator 与核心业务无耦合,可安全删除。若不需要定时任务或代码生成功能,每个模块只需三步即可移除:
- 删除模块目录
- 从父 POM 的
<modules>中移除对应的<module> - 从 ruoyi-admin 的
<dependencies>中移除对应依赖
quartz 模块还需额外删除数据库中的 qrtz_* 表,generator 模块需删除 gen_table 和 gen_table_column 表。
父工程的统一管理
在多模块设计中,根目录下的父工程不写代码,只提供 pom 文件,承担三项核心职责:聚合子模块、统一版本管理、配置构建环境。
聚合子模块
父工程的打包方式设为 pom,自身不参与打包,仅用作子模块的管理容器:
<modules>
<module>ruoyi-admin</module>
<module>ruoyi-framework</module>
<module>ruoyi-system</module>
<module>ruoyi-quartz</module>
<module>ruoyi-generator</module>
<module>ruoyi-common</module>
</modules>
<packaging>pom</packaging>
<modules> 标签声明哪些子目录属于本项目的子模块。配置后,在根目录执行一条构建命令就能让 Maven 按依赖关系自动排列构建顺序,若依的构建顺序为:common → system → framework → quartz → generator → admin。
统一版本管理
父工程通过 <properties> 定义版本号变量,通过 <dependencyManagement> 声明受管控的依赖及其版本:
<properties>
<spring-boot.version>3.5.11</spring-boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencyManagement> 只声明版本,不引入依赖。子模块在自己的 <dependency> 中引用这些依赖时可以省略 <version>,由父工程统一管控。所有模块使用同一框架时不会出现版本不一致的问题,升级时只需改父 POM 的一处变量。
配置构建环境
父工程统一管理构建插件和远程仓库地址:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<parameters>true</parameters>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
</plugin>
</plugins>
</build>
在父 POM 的 <build><plugins> 中直接声明的插件会被所有子模块继承。同时父工程还配置了阿里云镜像仓库,所有子模块下载依赖和插件时自动使用该地址,无需重复配置。
子模块的声明与继承
每个子模块在自身的 pom 文件中声明父工程:
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.9.2</version>
</parent>
建立继承关系后,子模块自动获得父工程的版本管控、插件配置和仓库地址。子模块的 groupId 和 version 与父工程一致时可以省略,只需保留 artifactId。
admin 模块结构
admin 是整个框架的后端入口,包含了启动类、所有 Controller 和配置文件:
ruoyi-admin
├── pom.xml
└── src/main/
├── java/com/ruoyi/
│ ├── RuoYiApplication.java # 启动类
│ ├── RuoYiServletInitializer.java # Web容器部署初始化器
│ └── web/
│ ├── controller/
│ │ ├── common/ # 公共接口(验证码、文件上传)
│ │ ├── monitor/ # 监控接口(缓存、服务器、日志)
│ │ ├── system/ # 系统管理接口(用户/角色/菜单等)
│ │ └── tool/ # 工具接口
│ └── core/config/
│ └── SwaggerConfig.java # API文档配置
└── resources/
├── application.yml # 主配置文件
├── application-druid.yml # 数据源配置
└── logback.xml # 日志配置
common 模块结构
common 是所有模块需要的公共基础层,定义了注解、常量、异常、工具类和实体类:
ruoyi-common/src/main/java/com/ruoyi/common/
├── annotation/ # 自定义注解(@Log、@DataScope、@DataSource、@RateLimiter 等)
├── config/ # 配置类(项目配置、脱敏序列化)
├── constant/ # 常量(缓存key、状态码、用户常量等)
├── core/
│ ├── controller/ # Controller基类
│ ├── domain/ # 统一返回对象(AjaxResult、BaseEntity、分页对象)
│ ├── redis/ # Redis工具类
│ └── text/ # 字符集/类型转换工具
├── enums/ # 枚举(操作类型、数据源类型、限流类型等)
├── exception/ # 异常体系(业务异常、文件异常、用户异常)
├── filter/ # 过滤器(XSS防护、防盗链、可重复读)
└── utils/ # 工具类(字符串、日期、文件、安全、HTTP等)
其余模块的内部结构遵循标准的分层模式:system 按 domain/mapper/service 组织;framework 按功能域组织(aspectj/config/security/web);quartz 和 generator 各自独立维护 domain/mapper/service/util 结构。
admin 的构建插件
在所有子模块中,只有启动模块 ruoyi-admin 额外配置了构建插件:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<addResources>true</addResources>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
只有 admin 需要打成可执行的 fat jar,其余模块打成普通 jar 供依赖传递。repackage 目标将普通 jar 重新打包为包含所有依赖的可执行 fat jar,可以直接用 java -jar 运行。
不继承 starter-parent 的 SpringBoot 接入
若依的根 pom 中没有继承 spring-boot-starter-parent,原因是 Maven 的 <parent> 是单继承——子模块的父工程必须是 com.ruoyi:ruoyi,没有多余的继承位留给 starter-parent。
若依在自有父 POM 中通过 BOM import 引入 SpringBoot 的版本管理,再手动补齐编译配置和插件声明,达到等价效果:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<type>pom</type> 声明引入的是 POM 构件,<scope>import</scope> 将其 <dependencyManagement> 合并到当前父工程中。这是 Spring 官方文档推荐的多模块项目做法。
⚠️ <dependencyManagement> 只管理版本、不引入依赖。import 了 BOM 之后,子模块要用哪些依赖仍需自己写 <dependency> 声明(只是可以省略 <version>)。"import 了 BOM 就能直接用 Spring 的类"是误解。
工程化思考
插件声明位置:若依把 spring-boot-maven-plugin 直接写在父 POM 的 <build><plugins> 里,而不是 <pluginManagement>。<build><plugins> 的语义是"所有子模块执行该插件",但这里实际上依赖了"不绑定 execution 则插件不执行"这一隐式规则——只有 admin 显式绑定了 repackage,所以只有 admin 真正生效,其余模块不受影响。更规范的写法是父 POM 用 <pluginManagement> 统一插件版本和默认配置,admin 里单独声明并绑定 execution,意图更明确。若依的写法能正确工作且无副作用,但可读性稍差。
依赖传递 vs 显式声明:ruoyi-admin 不需要直接声明对 ruoyi-common 的依赖,因为通过 framework → system → common 的传递链可以自动获得。但若依选择让每个模块只声明直接依赖,这种做法降低了耦合的显式程度——未来如果调整传递链,上层的隐式依赖可能失效。在大型项目中,对关键依赖做显式声明是一种防御性编程策略。
打包灵活性:admin 同时配置了 spring-boot-maven-plugin 和 maven-war-plugin,意味着它既可以打成可执行 jar(默认),也可以打成 war 部署到外部 Tomcat。这是若依为不同部署场景预留的工程化考量。

浙公网安备 33010602011771号