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>
为提高代码可读性,建议使用 none
或 null
等明确名称。
更清晰的写法是直接清空 phase
参数:
<execution>
<id>enforce-file-exists</id>
<phase/>
</execution>
由于执行阶段为空,目标不会绑定到任何运行的构建阶段,从而禁用插件。
运行构建时,子模块的 enforce-file-exists
不会执行。
4. 总结
本文讨论了禁用父 POM 插件的场景。虽然禁用插件可能不是最佳方案(Maven 更推崇约定优于配置),但在特定情况下是必要的。
我们通过禁用父 POM 声明的 maven-enforcer-plugin
演示了两种方法:
- 优先使用插件的
skip
参数(最符合 Maven 约定) - 清空插件的
phase
参数(当插件不支持skip
时)
示例代码可在 GitHub 获取。