Bootstrap

若依框架中根目录与子模块 `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 的版本:

<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 文件里,我们需要再次引用这个依赖:

<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> 显式声明依赖才能使其生效。
;