源本科技 | 码上会

Maven 分模块开发

2026/03/17
8
0

从单体到模块化

随着软件系统规模的日益庞大,传统的“单体式”项目结构(所有代码堆砌在一个工程中)逐渐暴露出诸多弊端:代码耦合度高、编译速度慢、团队协作冲突频繁、复用性差等。为了解决这些问题,Maven 分模块开发(Multi-Module Project) 成为了 Java 企业级开发的标准实践。

什么是分模块开发

分模块开发是指将一个庞大的项目按照业务功能技术层级拆分成若干个独立的子模块(Sub-modules)。

  • 逻辑拆分:例如将项目拆分为 common(通用工具)、dao(数据访问)、service(业务逻辑)、web(控制层)等模块。

  • 物理隔离:每个模块拥有独立的 pom.xml 和源代码目录,但在逻辑上它们属于同一个父工程。

  • 依赖复用:模块之间像引用第三方 JAR 包一样相互引用,实现代码的高度复用和解耦。

核心目标:通过“高内聚、低耦合”的设计原则,提升代码的可维护性、可扩展性,并支持团队并行开发。


模块化开发优势

采用 Maven 多模块架构,能为项目带来显著的收益:

优势维度

详细说明

提高可维护性

每个模块职责单一,代码结构清晰
开发者只需关注特定模块的逻辑,降低了理解整个系统的认知负担

增强可扩展性

新增功能时,只需创建新模块或在现有模块中扩展,无需改动其他无关模块
降低了回归测试的风险

促进组件重用

通用模块(如 utils, core)可以被多个不同的项目引用,避免重复造轮子
实现“一次开发,多处使用”

简化构建与部署

增量编译
修改某个模块时,Maven 智能判断只需重新编译该模块及其依赖模块,大幅提升构建速度

独立测试
各模块可独立进行单元测试和集成测试

灵活部署
可根据需要单独部署某些微服务模块

统一依赖管理

父工程可以集中管理所有子模块的依赖版本
避免子模块间版本冲突,确保技术栈一致性


构建多模块项目

构建一个标准的 Maven 多模块项目通常遵循以下四个步骤:

第一步:创建父工程

父工程是整个项目的“骨架”,它本身不包含源代码,主要作用是聚合子模块统一管理依赖

  1. 创建项目:使用 IDE 或命令行创建一个普通的 Maven 项目。

  2. 关键配置:修改父工程的 pom.xml

    • <packaging>:必须设置为 pom。这是标识该项目为聚合项目的关键。

    • <modules>:列出所有子模块的名称。

    • <groupId><version>:定义组织 ID 和版本号,所有子模块将默认继承这两个属性。

父工程 pom.xml 示例

<project>
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>cloud-native-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging> <!-- 关键点:类型为 pom -->

    <name>Cloud Native Parent</name>
    <description>父工程,用于聚合和管理子模块</description>

    <!-- 聚合子模块列表 -->
    <modules>
        <module>common</module>
        <module>dao</module>
        <module>service</module>
        <module>web</module>
    </modules>

    <!-- 统一依赖管理 (可选但推荐) -->
    <dependencyManagement>
        <dependencies>
            <!-- 在这里统一定义所有子模块可能用到的依赖版本 -->
        </dependencies>
    </dependencyManagement>
</project>

第二步:创建子模块

在父工程目录下,为每个功能单元创建子模块。

  1. 目录结构:通常在父工程根目录下直接创建文件夹,如 common/, dao/ 等。

  2. 关键配置:每个子模块的 pom.xml 必须包含 <parent> 标签,指向父工程。

    • 子模块只需定义自己的 <artifactId>

    • <groupId><version> 默认继承自父工程(也可显式覆盖,但不推荐)。

    • <packaging> 默认为 jar(除非是特殊的 war 模块)。

子模块 pom.xml 示例 ( 以 common 模块为例 )

<project>
    <modelVersion>4.0.0</modelVersion>

    <!-- 指向父工程 -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>cloud-native-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath> <!-- 相对路径,IDE通常自动识别 -->
    </parent>

    <!-- 仅需定义模块自身的 artifactId -->
    <artifactId>common</artifactId>
    <packaging>jar</packaging>
    
    <name>Common Utils Module</name>

    <!-- 当前模块的依赖 -->
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
    </dependencies>
</project>

第三步:管理模块间依赖

模块之间的调用通过 Maven 依赖机制实现。

  • 场景:假设 service 模块需要调用 common 模块的工具类,web 模块需要调用 service 模块的业务逻辑。

  • 操作:在依赖方的 pom.xml 中,将被依赖方作为一个普通的 <dependency> 引入。

    • 注意:此时 groupIdversion 通常可以省略,因为它们会继承自父工程,只需指定 artifactId

service 模块依赖 common 模块示例

<dependencies>
    <!-- 依赖同项目的 common 模块 -->
    <dependency>
        <groupId>com.example</groupId> <!-- 可省略,继承父工程 -->
        <artifactId>common</artifactId> <!-- 必须指定 -->
        <version>1.0.0-SNAPSHOT</version> <!-- 可省略,继承父工程 -->
    </dependency>
</dependencies>

第四步:构建与安装

多模块项目的构建必须在父工程根目录下执行。

  • 命令mvn clean install

  • 执行逻辑

    1. Maven 读取父工程的 <modules> 列表。

    2. 根据模块间的依赖关系,自动计算构建顺序(例如:先编译 common,再编译 dao,最后编译 service)。

    3. 依次对每个模块执行 cleaninstall 生命周期。

    4. 最终,所有模块的 JAR 包都会被安装到本地仓库 (~/.m2/repository),供其他项目或本项目的其他模块使用。