若依框架中根目录与子模块 `pom.xml` 的区别

前言

在使用 Maven 构建的多模块项目中,比如若依(RuoYi)这样的后台管理系统,我们会遇到两种不同作用的 pom.xml 文件:位于项目根目录下的以及每个子模块下的。这两者之间存在一些关键差异,并且理解这些差异对于正确配置和管理项目至关重要。

根目录下的 pom.xml

根目录下的 pom.xml 主要作为父 POM 文件,它承担着以下几个重要职责:

  • 依赖管理 :通过 <dependencyManagement> 部分定义全局的依赖版本。这样,在所有子模块引用相同依赖时就不需要再指定版本号,从而确保整个项目的版本一致性。
  • 模块声明 :利用 <modules> 标签列出所有的子模块。这样做使得 Maven 可以统一管理和构建整个多模块项目。
  • 插件管理:定义了构建过程中使用的各种插件及其版本,保证所有子模块采用相同的构建工具集。
  • 公共属性:设置一些基础属性,如 Java 版本等,方便子模块复用。
子模块(如 ruoyi-admin)下的 pom.xml

相比之下,每个子模块内的 pom.xml 则更加专注于具体的实现细节:

  • 继承父 POM :通过 <parent> 标签来继承根目录下 pom.xml 中定义的各种配置,包括但不限于依赖版本和构建插件。
  • 特定依赖声明 :即使某个依赖已经在父 POM 中被管理了,子模块仍需显式地声明它。这是因为 <dependencyManagement> 仅用于预设版本信息而不实际引入依赖;只有当子模块明确指定了一个依赖时,Maven 才会真正将其加入到项目的类路径中。
  • 模块特有配置:根据自身需求对构建过程进行额外定制,例如添加或覆盖某些特定的构建插件配置。
为什么子模块仍需声明依赖
  1. 明确性:通过在子模块中明确声明所需依赖,确保构建过程中能够准确无误地包含这些库。
  2. 选择性引入:不同的子模块可能只关心父 POM 管理的部分依赖。因此,按照实际需要引入依赖可以避免加载不必要的库,有助于保持项目的简洁性和性能。
为什么根目录下的 pom.xml 引用了依赖,子模块下还要再次引用?

在 Maven 项目中,根目录下的 pom.xml 使用 <dependencyManagement> 来管理依赖的版本,但并不实际引入这些依赖。具体来说,<dependencyManagement> 仅仅是一个版本信息的集中管理器,它告诉 Maven 如果某个依赖在子模块中被引用时应该使用哪个版本,但它并不会将这些依赖实际添加到项目的类路径中。

为了使这些依赖真正可用,子模块必须在自己的 pom.xml 文件中通过 <dependencies> 部分显式地声明这些依赖。这种设计有以下几点好处:

  1. 灵活性:不同的子模块可以根据自己的需求选择性地引入依赖,而不是强制所有子模块都使用相同的依赖集合。
  2. 清晰性 :子模块的 pom.xml 明确列出了其实际使用的依赖,使得项目结构更加清晰,便于维护。
  3. 避免冗余:如果某个子模块不需要某个依赖,就不必在该子模块中引入,从而减少了项目的复杂性和潜在的冲突。
实际示例

假设我们在若依项目中创建了一个新的业务模块 ruoyi-student。首先,在根目录的 pom.xml 中,我们通过 <dependencyManagement> 定义了 MyBatis Plus 的版本:

xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ruoyi</groupId>
    <artifactId>ruoyi</artifactId>
    <version>3.8.6</version>
    <packaging>pom</packaging>

    <properties>
        <mybatis-plus.version>3.4.3.4</mybatis-plus.version>
        <!-- 其他属性 -->
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>${mybatis-plus.version}</version>
            </dependency>
            <!-- 更多依赖 -->
        </dependencies>
    </dependencyManagement>

    <modules>
        <module>ruoyi-admin</module>
        <module>ruoyi-student</module>
        <!-- 其他子模块 -->
    </modules>

    <!-- 插件管理和其他配置 -->
</project>

然后,在 ruoyi-student 模块的 pom.xml 文件里,我们需要再次引用这个依赖:

xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.ruoyi</groupId>
        <artifactId>ruoyi</artifactId>
        <version>3.8.6</version>
    </parent>
    <artifactId>ruoyi-student</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <!-- 其他特定于该模块的依赖 -->
    </dependencies>

    <!-- 模块特有配置 -->
</project>

这里并没有重复指定版本号,因为这已经由父 POM 管理好了。

结语

了解并正确应用这两种 pom.xml 的特性,可以帮助开发者更好地组织和维护复杂的多模块项目。希望这篇博客能够帮助您加深对 Maven 项目结构的认识,并为您的开发工作提供一定的指导。如果您还有更多关于若依或其他相关技术的问题,欢迎继续探讨!

总结

  • 根目录 pom.xml 负责全局配置,包括依赖版本管理、模块声明和插件管理。
  • 子模块 pom.xml 继承根目录 pom.xml 的配置,并根据自身需求声明具体依赖和特有配置。
  • 子模块需要显式声明依赖 是为了确保依赖被正确引入,并且可以根据需要选择性地引入依赖。
  • 根目录下的 pom.xml 引用了依赖,子模块下还需要再次引用 是因为 <dependencyManagement> 仅管理版本信息,不实际引入依赖,子模块需要通过 <dependencies> 显式声明依赖才能使其生效。
相关推荐
无所事事O_o6 分钟前
JAVA应用不定时卡顿问题排查过程记录
java·优化
Hello--_--World10 分钟前
Vue指令:v-if vs v-show、v-if 与 v-for 的优先级冲突、自定义指令
前端·javascript·vue.js
神の愛11 分钟前
ReactHooks
前端·javascript·react.js
蝎子莱莱爱打怪17 分钟前
用好CC,事半功倍!Claude Code 命令大全,黄金命令推荐、多模型配置、实践指南、Hooks 和踩坑记录大全
前端·人工智能·后端
幸福巡礼21 分钟前
【LangChain 1.2 实战(八)】Agent Middleware 实战 —— 动态路由、监控、安全与容错
java·安全·langchain
本末倒置18329 分钟前
VS Code 这次稳了!CSS Anchor Positioning 彻底终结 WebView 定位卡顿
前端
MonkeyKing71551 小时前
Flutter状态管理实战:全局、局部、页面状态拆分指南
前端·flutter
Panzer_Jack1 小时前
Copiwaifu:一个和 Claude Code、Codex、Copilot 等 AI 编程工具联动的 Live2D 桌宠[特殊字符]
前端·人工智能·copilot·web·live2d·pixi.js·easy-live2d
Byron__1 小时前
Java JVM核心知识点复习笔记
java·jvm·笔记
程序员小白条1 小时前
别盲目卷算法!2026 程序员\&大学生,最稳的 AI 技术进阶路线全梳理
java·网络·人工智能·网络协议·http·面试