Maven之多模块项目管理

Maven之多模块项目管理

随着功能迭代,大型Java项目代码量和依赖关系会变得复杂,将项目拆分为多个模块,通过Maven进行统一管理,能显著提升代码复用性和可维护性。

一、为什么需要多模块项目?

小型项目可以用单模块开发,但大型项目(如电商系统、ERP系统)若采用单模块,会面临以下问题:

  • 代码耦合严重:所有功能(订单、支付、用户)混在一个模块,修改一处可能影响其他功能;
  • 构建效率低:即使只修改一行代码,也需重新构建整个项目;
  • 团队协作困难:多人开发时容易出现代码冲突;
  • 复用性差:通用功能(如工具类)无法被其他项目复用。

多模块项目的优势

多模块项目通过"按功能拆分模块"解决上述问题,核心优势:

  • 职责分离 :每个模块专注单一功能(如user-module处理用户相关,order-module处理订单相关);
  • 按需构建:修改某个模块后,只需构建该模块及依赖它的模块;
  • 团队并行开发:不同团队负责不同模块,减少冲突;
  • 功能复用 :通用模块(如common-module)可被多个项目引用;
  • 版本统一:通过父模块统一管理依赖版本,避免版本冲突。

二、多模块项目的结构设计

多模块项目的核心是"父模块+子模块"的层级结构,父模块负责统一配置,子模块负责具体功能。

2.1 基础结构

以"电商系统"为例,典型的模块拆分:

复制代码
ecommerce-parent(父模块,pom类型)
├── ecommerce-common(子模块:通用工具类、常量)
├── ecommerce-user(子模块:用户管理)
├── ecommerce-order(子模块:订单管理)
└── ecommerce-web(子模块:Web接口,依赖user和order模块)

模块职责:

  • 父模块(ecommerce-parent):无业务代码,仅负责依赖版本管理、插件配置;
  • common模块:存放所有模块共用的代码(如工具类、异常定义、实体类);
  • 业务模块(user、order):实现核心业务逻辑(Service、Mapper);
  • web模块:提供Web接口(Controller),依赖业务模块,是项目的入口。

2.2 模块依赖原则

模块间依赖需遵循"单向依赖",避免循环依赖(如A依赖B,B又依赖A),否则会导致构建失败。

合理依赖示例:

复制代码
web → order → common
web → user → common

(web依赖order和user,order和user依赖common,无循环)

三、创建多模块项目的完整流程

以IDEA为例,演示多模块项目的创建步骤(命令行创建类似,核心是mvn archetype:generate)。

3.1 步骤1:创建父模块(Parent)

父模块是"pom类型"(仅用于管理子模块,无代码),创建流程:

  1. 新建Maven项目,选择"Create from archetype"→"maven-archetype-quickstart"(或直接创建空项目);
  2. 填写父模块信息:
    • GroupId:com.example(组织ID)
    • ArtifactId:ecommerce-parent(父模块ID)
    • Version:1.0.0
  3. 修改pom.xml,设置打包类型为pom(父模块必须):
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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.example</groupId>
    <artifactId>ecommerce-parent</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging> <!-- 父模块必须为pom类型 -->
    <name>ecommerce-parent</name>
    <description>电商系统父模块</description>

    <!-- 后续添加子模块和依赖管理配置 -->
</project>

3.2 步骤2:创建子模块

在父模块下创建子模块(以ecommerce-common为例):

  1. 右键父模块→New→Module,选择Maven,ArtifactId填写ecommerce-common;
  2. 子模块的pom.xml会自动添加父模块引用:
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <!-- 继承父模块 -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>ecommerce-parent</artifactId>
        <version>1.0.0</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <artifactId>ecommerce-common</artifactId>
    <name>ecommerce-common</name>
    <description>通用工具模块</description>

    <!-- 子模块自身的依赖 -->
    <dependencies>
        <!-- 例如:添加lombok依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>
  1. 重复上述步骤,创建ecommerce-user、ecommerce-order、ecommerce-web模块。

3.3 步骤3:父模块配置子模块

父模块的pom.xml需通过modules标签声明子模块,否则Maven无法识别:

xml 复制代码
<!-- ecommerce-parent/pom.xml -->
<project>
    <!-- 基本信息省略 -->
    <packaging>pom</packaging>

    <!-- 声明子模块(路径为子模块目录) -->
    <modules>
        <module>ecommerce-common</module>
        <module>ecommerce-user</module>
        <module>ecommerce-order</module>
        <module>ecommerce-web</module>
    </modules>
</project>

注意 :子模块目录必须与module标签中的名称一致(如module为ecommerce-common,则子模块目录必须是ecommerce-common)。

四、多模块项目的依赖管理

多模块项目的核心是"通过父模块统一管理依赖版本",避免各模块版本不一致导致的冲突。

4.1 父模块统一版本管理

通过properties定义版本变量,dependencyManagement集中管理依赖:

xml 复制代码
<!-- ecommerce-parent/pom.xml -->
<project>
    <properties>
        <!-- 定义版本变量 -->
        <spring.version>5.3.20</spring.version>
        <mybatis.version>3.5.9</mybatis.version>
        <lombok.version>1.18.24</lombok.version>
        <junit.version>4.13.2</junit.version>
    </properties>

    <!-- 依赖版本管理(子模块引用时无需指定version) -->
    <dependencyManagement>
        <dependencies>
            <!-- Spring相关 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <!-- MyBatis -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>${mybatis.version}</version>
            </dependency>

            <!-- Lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>

            <!-- 测试 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>

            <!-- 子模块之间的依赖(也需在此声明版本) -->
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>ecommerce-common</artifactId>
                <version>${project.version}</version> <!-- 与父模块版本一致 -->
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

核心作用:

  • properties集中定义版本,修改时只需改一处;
  • dependencyManagement声明依赖版本,子模块引用时无需指定version,自动使用父模块定义的版本;
  • 子模块的依赖也需在父模块声明(如ecommerce-common),确保所有模块引用的是同一版本。

4.2 子模块引用依赖

子模块引用父模块管理的依赖时,无需指定version:

xml 复制代码
<!-- ecommerce-common/pom.xml -->
<dependencies>
    <!-- 引用lombok(版本由父模块控制) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <!-- 无需指定version -->
    </dependency>
</dependencies>

<!-- ecommerce-user/pom.xml -->
<dependencies>
    <!-- 引用common模块(依赖其他子模块) -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>ecommerce-common</artifactId>
        <!-- 版本由父模块控制 -->
    </dependency>

    <!-- 引用Spring(版本由父模块控制) -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
</dependencies>

<!-- ecommerce-web/pom.xml -->
<dependencies>
    <!-- 依赖user和order模块 -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>ecommerce-user</artifactId>
    </dependency>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>ecommerce-order</artifactId>
    </dependency>

    <!-- SpringMVC(Web模块特有依赖) -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
    </dependency>
</dependencies>

4.3 插件管理(build)

除了依赖,插件版本也可通过父模块统一管理:

xml 复制代码
<!-- ecommerce-parent/pom.xml -->
<build>
    <!-- 插件版本管理 -->
    <pluginManagement>
        <plugins>
            <!-- 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>

            <!-- 打包插件(Web模块需要) -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

子模块引用插件时无需指定版本:

xml 复制代码
<!-- ecommerce-web/pom.xml(Web模块需要打包为war) -->
<build>
    <plugins>
        <!-- 引用父模块管理的打包插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <!-- 无需指定version -->
        </plugin>
    </plugins>
</build>

五、多模块项目的构建与运行

5.1 构建项目

5.1.1 构建整个项目

在父模块目录执行mvn clean install,Maven会按依赖顺序构建所有模块:

bash 复制代码
cd ecommerce-parent
mvn clean install

构建顺序 :Maven会自动分析依赖,按common → user → order → web的顺序构建(依赖者后构建)。

5.1.2 构建单个模块

修改某个模块后,可单独构建该模块(及依赖它的模块):

bash 复制代码
# 构建ecommerce-user模块
cd ecommerce-parent
mvn clean install -pl ecommerce-user -am
  • -pl:指定构建的模块(ecommerce-user);
  • -am:同时构建该模块依赖的模块(如ecommerce-user依赖common,则先构建common)。

5.2 运行Web模块

ecommerce-web作为入口模块(假设是SpringMVC项目),可通过Tomcat插件运行:

  1. 在ecommerce-web的pom.xml添加Tomcat插件:
xml 复制代码
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat9-maven-plugin</artifactId>
            <version>3.0.0</version>
            <configuration>
                <port>8080</port>
                <path>/</path>
            </configuration>
        </plugin>
    </plugins>
</build>
  1. 运行命令:
bash 复制代码
cd ecommerce-web
mvn tomcat9:run
  1. 访问http://localhost:8080即可调用Web接口。

六、常见问题与避坑指南

6.1 循环依赖(Circular Dependency)

错误 :The projects in the reactor contain a cyclic reference

原因 :模块间存在循环依赖(如user依赖order,order又依赖user)。

解决方案:

  • 重构代码,将循环依赖的部分提取到common模块;
  • 通过接口或事件机制解耦(如user调用order的接口,而非直接依赖类)。

6.2 子模块找不到父模块(Parent Not Found)

错误 :Could not find artifact com.example:ecommerce-parent:pom:1.0.0

原因:

  • 父模块未安装到本地仓库(未执行mvn install);
  • 子模块的parent配置错误(GAV与父模块不一致)。

解决方案:

  • 先在父模块执行mvn clean install,将父模块安装到本地仓库;
  • 检查子模块pom.xml的parent配置,确保groupId、artifactId、version与父模块一致。

6.3 子模块依赖其他子模块失败

错误 :Could not find artifact com.example:ecommerce-common:jar:1.0.0

原因 :被依赖的模块(如common)未安装到本地仓库。

解决方案:

  • 先构建被依赖的模块(mvn clean install -pl ecommerce-common);
  • 确保依赖的groupId、artifactId正确(与被依赖模块一致)。

6.4 多模块项目的资源文件问题

问题 :子模块的src/main/resources资源文件未被打包到jar中。

原因:Maven默认会打包资源文件,但如果是自定义目录,需手动配置。

解决方案 :在父模块或子模块的pom.xml中配置资源插件:

xml 复制代码
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*</include>
            </includes>
        </resource>
        <!-- 若资源在java目录下 -->
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

总结:多模块项目的核心要点

  1. 结构设计:

    • 父模块(pom类型)负责版本管理和插件配置;
    • 子模块按功能拆分(common、业务模块、web模块),遵循单向依赖;
    • 避免循环依赖,否则无法构建。
  2. 依赖管理:

    • 通过父模块的dependencyManagement统一版本;
    • 子模块引用依赖时无需指定version,自动继承父模块版本;
    • 子模块间依赖需在父模块声明版本。
  3. 构建技巧:

    • 整体构建用mvn clean install(父模块目录);
    • 增量构建用-pl和-am参数,提高效率。

掌握多模块项目管理能显著提升大型项目的开发和维护效率,实际开发中,模块拆分不宜过细(避免模块过多导致管理复杂),应该以"一个模块对应一个独立功能"为原则。

若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!

ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ

相关推荐
2601_953824616 天前
基于SSM的水果超市管理系统
java·tomcat·maven
captain3766 天前
HTTP(2)
java·网络·http·java-ee
明月_清风7 天前
Maven 到底是什么?一篇文章搞懂 Java 项目构建与依赖管理
java·后端·maven
今年下半年7 天前
SpringBoot整合金蝶中间件
spring boot·中间件·maven
2501_933923258 天前
Spring Bean作用域揭秘:单例、原型、请求与会话的区别
java·后端·spring·java-ee
vx_BS813308 天前
【项目编号:project51629】Spring Boot 乡村自来水缴费系统:把抄表、水费生成与在线缴费做成一条数字化闭环
java·spring boot·eclipse·tomcat·maven
xieliyu.8 天前
JVM 垃圾回收机制详解:从标记过程、回收算法到垃圾收集器
java·jvm·笔记·java-ee
captain3769 天前
网络原理(9)-数据链路层
java·网络协议·java-ee
暮雨哀尘9 天前
JAVA基础练习(四):SpringBoot 实现简易登录功能
java·spring boot·eclipse·maven
hanchenxing9 天前
CI/CD流水线中的构建缓存:从原理到最小可运行示例CI/CD
maven·构建缓存