基于 Maven 的多模块项目架构

1. 关键 Maven 组件含义

在多模块项目中,以下四个标签构成了骨架的核心:

1.1 <modules>

  • 含义:聚合(Aggregation)。用于在父(根)项目中声明包含的子模块。
  • 作用:告诉 Maven:"当构建我(根项目)时,请顺带构建以下这些子文件夹"。它决定了 Maven 反应堆(Reactor)的扫描范围。
  • 代码示例(根 POM):
xml 复制代码
<modules>
    <module>dependencies</module>
    <module>server</module>
    <module>hmdianping</module>
</modules>

1.2 <dependencyManagement>

  • 含义:依赖版本锁定。
  • 作用 :它只声明依赖的 groupIdartifactIdversion不下载 Jar 包。它的作用是建立一个"版本字典",供子模块查询。
  • 代码示例(Dependencies 模块):
xml 复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.26</version>
        </dependency>
    </dependencies>
</dependencyManagement>

1.3 <dependencies>

  • 含义:依赖引入。
  • 作用 :真正的"下单"操作。Maven 会根据这里列出的坐标下载 Jar 包并加入 Classpath。如果在子模块中使用,且父工程/BOM 中已声明版本,则此处不写版本号
  • 代码示例(业务模块 POM):
xml 复制代码
<dependencies>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
    </dependency>
</dependencies>

1.4 <packaging>pom</packaging>

  • 含义:打包类型为 POM。
  • 作用 :声明该项目是一个"容器"或"配置清单",不包含 Java 代码,也不会生成 JAR 文件。
  • 适用场景:根项目(Root)、版本管理模块(BOM/Dependencies)。

2. 多模块项目介绍与各模块 POM 职责

标准架构通常分为三层:根项目 -> BOM 模块 -> 业务/启动模块

2.1 根项目 (Root)

  • 职责:全局总控。定义全局变量、聚合子模块、配置编译插件。
  • POM 内容
xml 复制代码
<groupId>cn.iocoder.boot</groupId>
<artifactId>SpringDataRedis</artifactId>
<version>${revision}</version>
<packaging>pom</packaging> <modules>
    <module>dependencies</module> <module>hmdianping</module>
</modules>

<properties>
    <revision>2026.2.4-jdk17-SNAPSHOT</revision> </properties>

<dependencyManagement>
     <dependency>
         <groupId>cn.iocoder.boot</groupId>
         <artifactId>dependencies</artifactId>
         <version>${revision}</version>
         <type>pom</type>
         <scope>import</scope>
         <relativePath>dependencies/pom.xml</relativePath> </dependency>
</dependencyManagement>

2.2 依赖管理模块 (Dependencies)

  • 职责:版本大管家。纯配置文件,不写代码。
  • POM 内容
xml 复制代码
<parent>
    <artifactId>SpringDataRedis</artifactId>
    <groupId>cn.iocoder.boot</groupId>
    <version>${revision}</version>
    <relativePath>../pom.xml</relativePath>
</parent>
<artifactId>dependencies</artifactId>
<packaging>pom</packaging>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.5.10</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>cn.iocoder.boot</groupId>
            <artifactId>hmdianping</artifactId>
            <version>${revision}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

2.3 业务模块 (hmdianping)

  • 职责:代码实现。
  • POM 内容 :使用 <dependencies> 引入所需 Jar 包(如 MyBatis-Plus),不写版本号。

2.4 启动模块 (Server)

  • 职责:程序入口。
  • POM 内容
  • 引用所有业务模块(如 hmdianping)。
  • 配置 spring-boot-maven-plugin 插件进行打包(Repackage)。

3. POM 文件是如何串联起来的

这几个文件通过继承聚合导入三种机制形成闭环:

  1. 向下聚合 :根 POM 通过 <modules> 找到 dependencieshmdianping,建立构建列表。
  2. 向上继承 :子模块通过 <parent> + <relativePath> 继承根 POM,从而获取 ${revision} 变量和插件配置。
  3. 横向导入
  • 根 POM 在 dependencyManagementimportdependencies 模块。
  • 业务模块在引用依赖时,Maven 会向上追溯到根 POM,根 POM 指向 dependencies 模块,从而解析出正确的版本号。

串联示意图:

Root POM (定义变量) <--(继承)-- Children (获取变量)

Root POM (引用 BOM) --(Import)--> Dependencies POM (提供版本)

Business POM (请求依赖) --(查表)--> Root POM --> Dependencies POM


4. 多模块构建流程 (mvn install)

当在根目录执行 mvn clean install 时:

  1. 解析阶段 :Maven 读取根 POM,解析 ${revision}2026.2.4-jdk17-SNAPSHOT
  2. 计算反应堆 (Reactor) :Maven 扫描 <modules>,分析依赖拓扑,计算出构建顺序:
  • Root -> dependencies -> hmdianping -> server
  1. 执行阶段
  • Root:安装根 POM 到本地仓库。
  • Dependencies:读取 pom.xml,将其安装到本地仓库(作为版本参考文件)。
  • Hmdianping :编译 Java 代码,利用 dependencies 提供的版本号下载 Jar 包,最终打成 hmdianping.jar 安装到仓库。
  • Server :编译启动类,将 hmdianping.jar 和其他三方包解压合并,打成可运行的 Fat-Jar。

5. 为什么继承 spring-boot-starter-parent 会报错

在自定义的多模块架构中,如果根 POM 写了 <parent> 继承 spring-boot-starter-parent,常报 Non-resolvable import POMCould not find artifact

原因分析:

  1. 继承链冲突:Maven 只能单继承。如果你继承了 Spring Boot,就无法形成"根项目作为所有子模块唯一父类"的闭环。
  2. 依赖查找死锁
  • 根 POM 继承 Spring Boot 后,Maven 会优先按照 Spring Boot 的规则初始化。
  • 此时根 POM 试图 import 本地的 dependencies 模块。
  • 由于 Maven 认为父类是远程的 Spring Boot,它会倾向于去远程/本地仓库查找 dependencies 模块,而忽略本地磁盘(Local Disk)。
  • 结果 :因为 dependencies 是你刚写的,仓库里没有,Maven 报错"找不到构件"。

解决方案:

  • 解耦 :根 POM 不要 继承 spring-boot-starter-parent
  • 组合 :在 dependencies 模块中通过 import 方式引入 spring-boot-dependencies
  • 本地路径 :在根 POM 引用 dependencies 时,必须强制指定 <relativePath>dependencies/pom.xml</relativePath>,告诉 Maven:"别去仓库找了,文件就在磁盘这个位置"。
相关推荐
min1811234562 小时前
多模态大语言模型发展现状与未来趋势:图文音视频跨模态理解的技术架构详解
语言模型·架构·音视频
短剑重铸之日2 小时前
《设计模式》第八篇:三大类型之创建型模式
java·后端·设计模式·创建型设计模式
野犬寒鸦3 小时前
从零起步学习并发编程 || 第四章:synchronized底层源码级讲解及项目实战应用案例
java·服务器·开发语言·jvm·后端·学习·面试
!停3 小时前
数据结构二叉树——堆
java·数据结构·算法
jiayong2310 小时前
DevOps体系详解02-技术架构与工具链
运维·架构·devops
virus594511 小时前
悟空CRM mybatis-3.5.3-mapper.dtd错误解决方案
java·开发语言·mybatis
没差c12 小时前
springboot集成flyway
java·spring boot·后端
时艰.12 小时前
Java 并发编程之 CAS 与 Atomic 原子操作类
java·开发语言
编程彩机12 小时前
互联网大厂Java面试:从Java SE到大数据场景的技术深度解析
java·大数据·spring boot·面试·spark·java se·互联网大厂