Maven聚合父工程管理子模块

wen java案例 1

本文目录导读:

Maven聚合父工程管理子模块

  1. 核心概念
  2. 目录结构示例
  3. 父工程 pom.xml 配置详解
  4. 子模块 pom.xml 配置详解
  5. dependencyManagementdependencies 的区别
  6. 常见问题与最佳实践
  7. 构建命令

Maven聚合父工程(通常称为pom打包方式的父项目)是管理多模块项目的核心方式,它主要解决两个问题:批量构建(聚合)和统一依赖管理(继承)。

以下是关于如何创建和管理 Maven 聚合父工程与子模块的详细指南。

核心概念

  1. 聚合(Aggregation)
    • 父工程的 pom.xml 中通过 <modules> 标签声明子模块。
    • 作用:当你在父工程目录执行 mvn clean install 时,Maven 会自动按照依赖关系顺序构建所有子模块。
  2. 继承(Inheritance)
    • 父工程的 pom.xml 中定义公共配置(如依赖版本、插件、仓库等)。
    • 子模块的 pom.xml 通过 <parent> 标签声明继承自哪个父工程。
    • 作用:消除重复配置,统一项目规范。

目录结构示例

假设项目名为 my-project,包含三个子模块:commonserviceweb

my-project/                     # 根目录(通常就是父工程)
├── pom.xml                     # 父工程的 POM,packaging 为 pom
├── my-project-common/          # 子模块1
│   └── pom.xml
├── my-project-service/         # 子模块2
│   └── pom.xml
└── my-project-web/             # 子模块3
    └── pom.xml

父工程 pom.xml 配置详解

父工程的 packaging 必须为 pom,这是聚合和管理子模块的前提。

<?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>my-project</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <!-- 关键点:打包方式必须是 pom -->
    <packaging>pom</packaging>
    <name>My Project Parent</name>
    <description>父工程,负责管理子模块和统一依赖</description>
    <!-- 1. 声明子模块(聚合) -->
    <modules>
        <module>my-project-common</module>
        <module>my-project-service</module>
        <module>my-project-web</module>
        <!-- 注意:module 标签里放的是子模块的目录名(相对路径) -->
    </modules>
    <!-- 2. 统一属性管理 -->
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- 统一管理第三方依赖版本 -->
        <spring.boot.version>3.2.0</spring.boot.version>
        <lombok.version>1.18.30</lombok.version>
        <mysql.connector.version>8.0.33</mysql.connector.version>
    </properties>
    <!-- 3. 依赖管理(关键:<dependencyManagement>) -->
    <!-- 这里只声明版本,不实际引入依赖 -->
    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot BOM(物料清单):引入后可以不用写版本号 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- 子模块通用的第三方依赖(在此声明版本) -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.connector.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!-- 4. 所有子模块都会继承的公共依赖(较少使用,一般放日志、lombok等) -->
    <dependencies>
        <!-- 所有子模块都需要 SLF4J -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.9</version>
        </dependency>
    </dependencies>
    <!-- 5. 统一插件管理 -->
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring.boot.version}</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.11.0</version>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

子模块 pom.xml 配置详解

my-project-service 为例:

<?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>
    <!-- 1. 声明父工程(继承) -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>my-project</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <!-- 相对路径:指向父工程的 pom.xml 文件 -->
        <relativePath>../pom.xml</relativePath>
    </parent>
    <!-- 2. 子模块自己的坐标 -->
    <!-- 注意:通常省略 groupId 和 version,它们会从父工程继承 -->
    <artifactId>my-project-service</artifactId>
    <!-- packaging 默认为 jar,如果是 web 模块可以用 war -->
    <packaging>jar</packaging>
    <name>My Project Service</name>
    <description>业务逻辑层模块</description>
    <!-- 3. 子模块自己的依赖 -->
    <dependencies>
        <!-- 依赖同一项目的其他子模块 -->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>my-project-common</artifactId>
            <!-- 注意:这里不需要写 version,因为父工程已管理 -->
        </dependency>
        <!-- 使用父工程管理的依赖,只需写 groupId 和 artifactId -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <!-- 版本号由父工程的 spring-boot-dependencies 管理 -->
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <!-- 版本由父工程的 <dependencyManagement> 管理 -->
        </dependency>
    </dependencies>
</project>

dependencyManagementdependencies 的区别

特性 <dependencies> (在父工程中) <dependencyManagement> (在父工程中)
作用 所有继承的子模块强制引入该依赖 声明依赖的版本号,子模块按需引入
是否被子模块继承 是,子模块自动拥有该依赖 否,子模块需要显式声明 dependency
典型场景 公共日志、Lombok、测试框架等 Spring Boot 版本、Jackson 版本等
子模块声明时 无需再次声明 必须声明,但可以省略 version

建议:父工程中尽量使用 <dependencyManagement> 管理版本,避免在父工程中直接放过多 <dependencies>,防止子模块被迫引入不需要的库。

常见问题与最佳实践

<relativePath> 要写吗?

  • 推荐写<relativePath>../pom.xml</relativePath> 可以提高构建的确定性。
  • 可选但建议:如果不写,Maven 会先尝试从本地仓库、远程仓库查找父 POM,如果你本地的父 POM 还没有安装到仓库,构建就会失败。

子模块可以不被父工程包含吗?

  • 可以,父工程只是通过 <modules> 管理你需要一起构建的模块,其他项目可以通过坐标直接引用你的子模块。

版本号冲突如何处理?

  • 原则:在父工程的 <dependencyManagement> 中统一定义所有关键依赖的版本,子模块中尽量避免写版本号。
  • 如果有必要在子模块中覆盖版本,可以在子模块的 <dependency> 中明确指定 version

模块间依赖顺序

  • service 依赖 common,Maven 构建时会自动先构建 common,再构建 service,你不需要担心顺序。

父工程本身不包含业务代码

  • 父工程的 src 目录通常可以删除,它只负责管理配置。packagingpom 的项目不需要 src/main/java

构建命令

  • 构建整个项目(在父工程目录下执行):

    mvn clean install
  • 只构建某个子模块及其依赖(在父工程目录下执行):

    mvn clean install -pl my-project-service -am
    • -pl:指定模块
    • -am:also make,表示同时构建该模块依赖的其他模块
  • 跳过测试构建

    mvn clean install -DskipTests

通过合理的父工程设计,你可以实现:

  1. 一键全量构建
  2. 零版本号冲突
  3. 统一的开发规范(编译器版本、编码格式)。

抱歉,评论功能暂时关闭!