Maven之多模块项目管理
-
- 一、为什么需要多模块项目?
- 二、多模块项目的结构设计
-
- [2.1 基础结构](#2.1 基础结构)
- [2.2 模块依赖原则](#2.2 模块依赖原则)
- 三、创建多模块项目的完整流程
-
- [3.1 步骤1:创建父模块(Parent)](#3.1 步骤1:创建父模块(Parent))
- [3.2 步骤2:创建子模块](#3.2 步骤2:创建子模块)
- [3.3 步骤3:父模块配置子模块](#3.3 步骤3:父模块配置子模块)
- 四、多模块项目的依赖管理
-
- [4.1 父模块统一版本管理](#4.1 父模块统一版本管理)
- [4.2 子模块引用依赖](#4.2 子模块引用依赖)
- [4.3 插件管理(build)](#4.3 插件管理(build))
- 五、多模块项目的构建与运行
-
- [5.1 构建项目](#5.1 构建项目)
-
- [5.1.1 构建整个项目](#5.1.1 构建整个项目)
- [5.1.2 构建单个模块](#5.1.2 构建单个模块)
- [5.2 运行Web模块](#5.2 运行Web模块)
- 六、常见问题与避坑指南
-
- [6.1 循环依赖(Circular Dependency)](#6.1 循环依赖(Circular Dependency))
- [6.2 子模块找不到父模块(Parent Not Found)](#6.2 子模块找不到父模块(Parent Not Found))
- [6.3 子模块依赖其他子模块失败](#6.3 子模块依赖其他子模块失败)
- [6.4 多模块项目的资源文件问题](#6.4 多模块项目的资源文件问题)
- 总结:多模块项目的核心要点
随着功能迭代,大型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类型"(仅用于管理子模块,无代码),创建流程:
- 新建Maven项目,选择"Create from archetype"→"maven-archetype-quickstart"(或直接创建空项目);
- 填写父模块信息:
- GroupId:
com.example
(组织ID) - ArtifactId:
ecommerce-parent
(父模块ID) - Version:
1.0.0
- GroupId:
- 修改
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
为例):
- 右键父模块→New→Module,选择Maven,ArtifactId填写
ecommerce-common
; - 子模块的
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>
- 重复上述步骤,创建
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插件运行:
- 在
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>
- 运行命令:
bash
cd ecommerce-web
mvn tomcat9:run
- 访问
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>
总结:多模块项目的核心要点
-
结构设计:
- 父模块(pom类型)负责版本管理和插件配置;
- 子模块按功能拆分(common、业务模块、web模块),遵循单向依赖;
- 避免循环依赖,否则无法构建。
-
依赖管理:
- 通过父模块的
dependencyManagement
统一版本; - 子模块引用依赖时无需指定
version
,自动继承父模块版本; - 子模块间依赖需在父模块声明版本。
- 通过父模块的
-
构建技巧:
- 整体构建用
mvn clean install
(父模块目录); - 增量构建用
-pl
和-am
参数,提高效率。
- 整体构建用
掌握多模块项目管理能显著提升大型项目的开发和维护效率,实际开发中,模块拆分不宜过细(避免模块过多导致管理复杂),应该以"一个模块对应一个独立功能"为原则。
若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ