1. 概述

Apache Maven是一个功能强大的工具,它使用插件自动执行 Java 项目中的所有构建和报告任务。

然而,在构建中可能会使用多个这些插件以及不同的版本和配置,特别是在多模块项目中。这可能会导致复杂的 POM 文件出现冗余或重复的插件工件以及分散在各个子项目中的配置的问题。

在这篇文章中,我们将看到如何使用Maven的插件管理机制来处理此类问题并有效地维护整个项目的插件。

2. 插件配置

Maven 有两种类型的插件:

  • 构建——在构建过程中执行。示例包括 Clean、Install 和 Surefire 插件。这些应该在 POM 的 构建 部分进行配置。
  • 报告——在站点生成期间执行以生成各种项目报告。示例包括 Javadoc 和 Checkstyle 插件。这些在项目 POM 的 报告 部分中配置。

Maven 插件提供执行和管理项目构建所需的所有有用功能。

例如,我们可以在POM中声明Jar插件:

<build>
    ....
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.3.0</version>
            ....
        </plugin>
    ....
    </plugins>
</build>

在这里,我们在 构建 部分包含了该插件,以添加将项目编译为 jar 的 功能。

3. 插件管理

除了 plugins 之外,我们还可以在POM的 pluginManagement 部分声明插件。它包含 插件 元素的方式与我们之前看到的非常相似。但是,通过在 pluginManagement 部分添加插件, 它就可供该POM以及所有继承的子POM使用

这意味着任何子 POM 只需在其 插件 部分引用插件即可继承插件执行。我们需要做的就是添加相关的 groupIdartifactId ,而无需重复配置或管理版本。

依赖管理机制类似,这在多模块项目中特别有用,因为它提供了一个中心位置来管理插件版本和任何相关配置。

4. 示例

让我们首先创建一个包含两个子模块的简单多模块项目。我们将在父 POM 中包含构建助手插件,其中包含几个帮助构建生命周期的小目标。在我们的示例中,我们将使用它将一些附加资源复制到子项目的项目输出中。

4.1.父 POM 配置

首先,我们将插件添加到父 POM 的 pluginManagement 部分:

<pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>build-helper-maven-plugin</artifactId>
            <version>3.3.0</version>
            <executions>
                <execution>
                    <id>add-resource</id>
                    <phase>generate-resources</phase>
                    <goals>
                        <goal>add-resource</goal>
                    </goals>
                    <configuration>
                        <resources>
                            <resource>
                                <directory>src/resources</directory>
                                <targetPath>json</targetPath>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>
   </plugins>
</pluginManagement>

这将插件的 add-resource 目标绑定到默认 POM 生命周期中的 generate-resources 阶段。我们还指定了包含附加资源的 src/resources 目录。插件执行将根据需要将这些资源复制到项目输出中的目标位置。

接下来,我们运行maven命令来确保配置有效并且构建成功:

$ mvn clean test

运行此命令后,目标位置尚不包含预期的资源。

4.2.子POM配置

现在,让我们从子 POM 中引用这个插件:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>build-helper-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

与依赖管理类似,我们不声明版本或任何插件配置。相反,子项目从父 POM 中的声明继承这些值。

最后,让我们再次运行构建并查看输出:

....
[INFO] --- build-helper-maven-plugin:3.3.0:add-resource (add-resource) @ submodule-1 ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ submodule-1 ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] Copying 1 resource to json
....

在这里,插件在构建期间执行,但仅在具有相应声明的子项目中执行。因此,项目输出现在包含来自指定项目位置的附加资源,如预期的那样。

我们应该注意, 只有 父 POM 包含插件声明和配置 ,而子项目只是根据需要引用它。

如果需要,子项目可以自由修改继承的配置

5. 核心插件

默认情况下,有一些 Maven核心插件用作构建生命周期的一部分。例如, clean编译器 插件不需要显式声明。

但是,我们可以在 POM 的 pluginManagement 元素中显式声明和配置它们。主要区别在于 核心插件配置自动生效,无需在子项目中进行任何引用

让我们通过将 编译器 插件添加到熟悉的 pluginManagement 部分来尝试一下:

<pluginManagement>
    ....
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
    ....
</pluginManagement>

在这里,我们锁定了插件版本并将其配置为使用 Java 8 来构建项目。但是,任何子项目中都不需要额外的 插件 声明。构建框架默认激活此配置。因此,此配置意味着构建必须使用 Java 8 来跨所有模块编译此项目。

总的来说, 显式声明配置并锁定多模块项目中所需的任何插件的版本可能是一个很好的做法 。因此,不同的子项目只能从父POM继承所需的插件配置,并根据需要应用它们。

这消除了重复声明、简化了 POM 文件并提高了构建的可重复性。

六,结论

在本文中,我们了解了如何集中和管理构建项目所需的 Maven 插件。

首先,我们查看了插件及其在项目 POM 中的用法。然后我们更详细地了解了 Maven 插件管理机制,以及它如何帮助减少重复并提高构建配置的可维护性。

与往常一样,示例代码可以在 GitHub 上获取。