Maven Build 配置实践

核心理解:Maven 的 <build> 配置本质上就是告诉 Maven —— "用什么插件、在什么时候、做什么事"。本文将围绕 pluginManagementplugins 的组合,总结出几种典型配置模式。


一、相关概念

1.1 官方定义

"Build plugins will be executed during the build and they should be configured in the <build/> element from the POM."

—— Maven 官方文档

1.2 pluginManagement vs plugins 区别

pluginManagement plugins
作用 定义插件的版本默认配置 实际执行插件
是否执行 不执行,仅声明 在当前模块执行
继承性 子模块可继承,但需显式声明 子模块默认继承
典型用途 父 POM 统一管理插件版本 当前模块真正使用的插件

1.3 插件的两种配置位置

配置位置 适用场景 示例
<pluginManagement> 父 POM 中统一定义版本和配置 compilersurefire 等几乎所有插件
<plugins> 直接执行插件 flattenspring-bootdocker

二、五种 Build 配置模式

模式一:父 POM 定义 + 子模块继承(最常用)

适用场景:多模块项目,所有子模块共享相同的插件配置。

父 POM 配置

<build>
    <pluginManagement>
        <plugins>
            <!-- 定义版本和配置,供所有子模块继承 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${mapstruct.version}</version>
                        </path>
                    </annotationProcessorPaths>
                    <compilerArgs>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0</version>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

子模块配置

<build>
    <plugins>
        <!-- 只需引用,不用写 version 和 configuration -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
        </plugin>
    </plugins>
</build>

流程图

父 POM
    │
    └── pluginManagement 定义 compiler 插件(版本 3.11.0,参数 -parameters)
            │
            ▼
子模块 A                            子模块 B
    │                                   │
    └── 引用 compiler 插件              └── 引用 compiler 插件
        版本和配置自动继承                  版本和配置自动继承

模式二:父 POM 直接执行(共享插件)

适用场景:所有模块(包括父 POM 自身)都需要执行的插件。

父 POM 配置

<build>
    <plugins>
        <!-- 版本管理插件:父 POM 和所有子模块都需要 -->
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>flatten-maven-plugin</artifactId>
            <version>${flatten-maven-plugin.version}</version>
            <configuration>
                <flattenMode>resolveCiFriendliesOnly</flattenMode>
                <updatePomFile>true</updatePomFile>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>flatten</goal>
                    </goals>
                    <phase>process-resources</phase>
                </execution>
                <execution>
                    <goals>
                        <goal>clean</goal>
                    </goals>
                    <phase>clean</phase>
                </execution>
            </executions>
        </plugin>
        
        <!-- 代码格式化插件:统一代码风格 -->
        <plugin>
            <groupId>com.diffplug.spotless</groupId>
            <artifactId>spotless-maven-plugin</artifactId>
            <version>2.43.0</version>
            <configuration>
                <java>
                    <googleJavaFormat/>
                </java>
            </configuration>
        </plugin>
    </plugins>
</build>

子模块:自动继承,无需任何配置。

父 POM
    │
    └── plugins 配置 flatten、spotless
            │
            ▼
子模块 A                         子模块 B
    │                                │
    └── 自动继承 flatten           └── 自动继承 flatten
        自动继承 spotless              自动继承 spotless

模式三:模块特有插件

适用场景:某些模块有特殊需求,需要额外插件(如 API 模块 vs Biz 模块)。

API 模块(只定义接口,不需要 Spring Boot 打包):

<build>
    <plugins>
        <!-- 仅需编译插件,继承自父 POM -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
        </plugin>
    </plugins>
</build>

BIZ 模块(需要 Spring Boot 打包 + Docker 镜像):

<build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
        <!-- 继承自父 POM -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
        </plugin>
        
        <!-- 模块特有:Spring Boot 打包 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>${spring.boot.version}</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        
        <!-- 模块特有:Docker 镜像构建 -->
        <plugin>
            <groupId>io.fabric8</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>0.43.4</version>
            <configuration>
                <images>
                    <image>
                        <name>${docker.registry}/${project.artifactId}:${project.version}</name>
                        <build>
                            <contextDir>${project.basedir}</contextDir>
                        </build>
                    </image>
                </images>
            </configuration>
        </plugin>
    </plugins>
</build>

模块对比

模块 编译插件 Spring Boot 打包 Docker 构建
-api 继承 不需要 不需要
-biz 继承 特有 特有

模式四:父子分离(定义与执行分离)—— 标准企业级实践

适用场景:大团队多模块项目,父 POM 统一定义,子模块按需引用或覆盖。

父 POM(只定义,不执行):

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0</version>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring.boot.version}</version>
            </plugin>
            <plugin>
                <groupId>io.fabric8</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.43.4</version>
            </plugin>
        </plugins>
    </pluginManagement>
    
    <!-- 父 POM 自身需要的插件 -->
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>flatten-maven-plugin</artifactId>
            <version>${flatten-maven-plugin.version}</version>
            <!-- 配置和执行 -->
        </plugin>
    </plugins>
</build>

子模块(按需引用,可覆盖配置):

<!-- API 模块:只需要编译 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <!-- version 和 configuration 继承父 POM -->
        </plugin>
    </plugins>
</build>

<!-- BIZ 模块:需要编译 + Spring Boot 打包 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

<!-- BIZ 模块如需覆盖父 POM 配置 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <!-- 重新配置,覆盖父 POM -->
            <configuration>
                <source>21</source>  <!-- 子模块使用更高版本 -->
                <target>21</target>
            </configuration>
        </plugin>
    </plugins>
</build>

模式五:内联配置(单体项目)

适用场景:简单单体项目,无需多模块继承。

<build>
    <finalName>myapp</finalName>
    <plugins>
        <!-- 所有插件直接配置完整信息 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
            <configuration>
                <source>17</source>
                <target>17</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>3.2.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>io.fabric8</groupId>
            <artifactId>docker-maven-plugin</artifactId>
            <version>0.43.4</version>
            <configuration>
                <images>
                    <image>
                        <name>myapp:latest</name>
                        <build>
                            <contextDir>${project.basedir}</contextDir>
                        </build>
                    </image>
                </images>
            </configuration>
        </plugin>
    </plugins>
</build>

三、模式选择决策树

build


四、最佳实践总结

4.1 配置原则

原则 说明
版本集中管理 所有插件版本在父 POM pluginManagement 中定义
按需引用 子模块只引用需要的插件,不写版本号
配置继承 通用配置在父 POM 中定义,特殊配置在子模块覆盖
职责分离 父 POM 负责"定义",子模块负责"使用"
模块对齐 API 模块只编译,BIZ 模块才打包和构建镜像

4.2 推荐的企业级配置结构

根父 POM
├── pluginManagement(定义所有插件版本和通用配置)
│   ├── maven-compiler-plugin      → 编译(含 Lombok + MapStruct)
│   ├── maven-surefire-plugin      → 测试(JUnit 5)
│   ├── maven-jar-plugin           → 打包
│   ├── spring-boot-maven-plugin   → Spring Boot 打包
│   ├── docker-maven-plugin        → Docker 构建
│   └── ... 其他插件
│
└── plugins(父 POM 自身需要)
    └── flatten-maven-plugin       → 统一版本管理

子模块 API
└── plugins
    └── maven-compiler-plugin      → 仅编译(继承父 POM 配置)

子模块 BIZ
└── plugins
    ├── maven-compiler-plugin      → 编译(继承)
    ├── spring-boot-maven-plugin   → 可执行 JAR(特有)
    └── docker-maven-plugin        → Docker 镜像(特有)

4.3 不同模块类型的配置要求

模块类型 打包类型 需要的插件
根父 POM pom flattenspotless
聚合模块 pom 无(继承父 POM 即可)
API 模块 jar compiler(继承)、source(可选)
BIZ 模块 jar compiler(继承)+ spring-boot + docker

五、快速参考

5.1 何时用 pluginManagement

  • 父 POM 中定义插件版本和配置
  • 让子模块使用统一版本的插件
  • 集中管理所有插件的配置

5.2 何时用 plugins

  • 父 POM 自身需要执行的插件(如 flatten
  • 子模块特有的插件(如 spring-bootdocker
  • 需要绑定到生命周期执行的插件

5.3 常见错误

错误 后果 正确做法
只在 pluginManagement 中定义,子模块不引用 插件不执行 子模块 <plugins> 中引用
子模块中写版本号 版本管理分散 省略版本,从父 POM 继承
plugins 中定义但不想让子模块继承 子模块被迫执行 在父 POM 的 pluginManagement 中定义
子模块覆盖父 POM 配置时写 <version> 可能版本不一致 省略版本,只写 <configuration> 覆盖