1. 概述

Maven 支持通过继承机制构建项目。当父 POM 定义了插件时,所有子模块都会继承该插件。

但如果我们不想继承父 POM 中的某个插件,又无法修改父 POM 该怎么办?

本文将探讨几种禁用 Maven 插件的方法,重点针对父 POM 中定义的 Maven Enforcer Plugin

2. 何时需要禁用父 POM 定义的插件?

在深入之前,先思考为什么需要这样做。

Maven 遵循约定优于配置原则。要记住:禁用插件可能是最快解决方案,但不一定是项目最佳实践。

当 Maven 项目的原作者未预见我们的使用场景,且我们无法自行修改父模块时,就可能需要禁用父 POM 中的插件。

假设原作者要求某个特定文件必须存在,但我们的模块不需要该文件。例如,父 POM 强制每个模块包含许可证文件,而我们的模块没有。与其添加一个令人困惑的空文件,不如直接禁用该规则。

通过在父模块中配置 maven-enforcer-plugin 来模拟此场景:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>3.0.0</version>
</plugin>

接着添加执行规则,要求每个模块的 src 目录下必须存在 file-that-must-exist.txt 文件:

<executions>
    <execution>
        <id>enforce-file-exists</id>
        <goals>
            <goal>enforce</goal>
        </goals>
        <configuration>
            <rules>
                <requireFilesExist>
                    <files>
                        <file>${project.basedir}/src/file-that-must-exist.txt</file>
                    </files>
                </requireFilesExist>
            </rules>
        </configuration>
    </execution>
</executions>

如果文件不存在,构建就会失败。

由于子模块会继承父模块的插件,所有子模块都必须遵守此规则。

下面我们看看如何在子 POM 中禁用该规则。

3. 如何禁用父 POM 定义的插件?

首先假设重构项目或修改父 POM 都不可行。如果能修改父模块,通过实现 pluginManagement 部分就能解决问题。

无法修改父模块的原因可能包括:

  • 我们不拥有项目,无权在模块外修改
  • 时间限制——重构项目耗时,直接在子模块禁用插件更方便

此外我们假设插件确实需要禁用。许多插件在非目标模块上也能正常运行。

例如,复制 Java 文件的插件在无 Java 文件的子项目中会跳过操作,不会引发问题。这种情况下保留插件运行更简单。

经过上述考虑后,如果确实需要禁用插件,可采用以下方法:

3.1. 配置 skip 参数

许多插件提供 skip 参数,可用于禁用插件。

查看 maven-enforcer-plugin 文档 可知它支持 skip 参数。

优先检查 skip 参数支持,这是最简单且最符合 Maven 约定的方案。

创建一个仅含 POM 的空子模块,执行 mvn clean install 会构建失败——因为继承了父模块规则但缺少必需文件。

在子 POM 中添加以下配置启用 skip 参数:

<plugin>
    <artifactId>maven-enforcer-plugin</artifactId>
    <configuration>
        <skip>true</skip>
    </configuration>
</plugin>

再次运行项目,构建成功。

但并非所有插件都支持 skip 参数。遇到这种情况该怎么办?

3.2. 移除 phase 参数

Maven 目标只有绑定到构建阶段才会执行。

在父 POM 中,我们为 enforce 目标配置了 enforce-file-exists 执行 ID。

由于未指定 phase 参数,它使用 enforce 目标的默认值。根据文档,默认绑定到 validate 阶段。

我们可以通过指定 phase 参数将目标绑定到其他构建阶段。

利用这一点,可将 phase 设置为不存在的值,使构建阶段永不执行,从而禁用插件:

<plugin>
    <artifactId>maven-enforcer-plugin</artifactId>
    <executions>
        <execution>
            <id>enforce-file-exists</id>
            <phase>any-value-that-is-not-a-phase</phase>
        </execution>
    </executions>
</plugin>

为提高代码可读性,建议使用 nonenull 等明确名称。

更清晰的写法是直接清空 phase 参数:

<execution>
    <id>enforce-file-exists</id>
    <phase/>
</execution>

由于执行阶段为空,目标不会绑定到任何运行的构建阶段,从而禁用插件。

运行构建时,子模块的 enforce-file-exists 不会执行。

4. 总结

本文讨论了禁用父 POM 插件的场景。虽然禁用插件可能不是最佳方案(Maven 更推崇约定优于配置),但在特定情况下是必要的。

我们通过禁用父 POM 声明的 maven-enforcer-plugin 演示了两种方法:

  1. 优先使用插件的 skip 参数(最符合 Maven 约定)
  2. 清空插件的 phase 参数(当插件不支持 skip 时)

示例代码可在 GitHub 获取。


原始标题:How to Disable a Maven Plugin Defined in a Parent POM | Baeldung