1. Overview
1.概述
In a Maven multi-module project, the effective POM is the result of merging all configurations defined within a module and its parents.
在Maven multi-module项目中,有效的POM是合并模块及其父模块中定义的所有配置的结果。
In order to avoid redundancies and duplication between modules, we often keep common configurations in the shared parent. However, there can be a challenge if we need to have a custom configuration for a child module without impacting all its siblings.
为了避免模块之间的冗余和重复,我们经常在共享的父模块中保留通用配置。然而,如果我们需要对一个子模块进行自定义配置而不影响其所有的兄弟姐妹,就会有一个挑战。
In this tutorial, we’ll learn how to override the parent plugin configuration.
在本教程中,我们将学习如何覆盖父插件的配置。
2. Default Configuration Inheritance
2.默认配置的继承性
Plugin configurations allow us to reuse a common build logic across projects. If the parent has a plugin, the child will automatically have it without additional configuration. This is like an inheritance.
插件配置使我们能够在不同的项目中重复使用一个共同的构建逻辑。如果父代有一个插件,子代将自动拥有该插件,而无需额外的配置。这就像是一种继承。
To achieve this, Maven merges the XML files at the element level. If the child defines an element with a different value, it replaces the one from the parent. Let’s see this in action.
为了实现这一目标,Maven在元素层面上合并XML文件。如果子代定义的元素有不同的值,它就会替换父代的元素。让我们来看看这个动作。
2.1. Project Structure
2.1.项目结构
First, let’s define a multi-module Maven project to experiment on. Our project will consist of one parent and two children:
首先,让我们定义一个多模块的Maven项目来进行实验。我们的项目将由一个父项目和两个子项目组成。
+ parent
+ child-a
+ child-b
Let’s say we want to configure the maven-compiler-plugin to use different Java versions between modules. Let’s configure our project to use Java 11 in general, but have child-a use Java 8.
假设我们想配置maven-compiler-plugin,让模块之间使用不同的Java版本。让我们把项目配置为普遍使用Java 11,但让child-a使用Java 8。
We’ll start with the parent configuration:
我们将从parent配置开始。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
<maxmem>512m</maxmem>
</configuration>
</plugin>
Here we’ve specified an additional property, maxmem, that we also want to use. However, we want child-a to have its own compiler settings.
这里我们指定了一个额外的属性,maxmem,我们也想使用这个属性。然而,我们希望child-a能有自己的编译器设置。
So, let’s configure child-a to use Java 8:
因此,让我们把孩子-a配置为使用Java 8。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
Now that we have our example, let’s see what this does to the effective POM.
现在我们有了我们的例子,让我们看看这对有效的POM有什么影响。
2.2. Understanding the Effective POM
2.2.了解有效的POM
The effective POM is affected by various factors, like inheritance, profiles, external settings, and so on. In order to see the actual POM, let’s run mvn help:effective-pom from the child-a directory:
有效的POM受到各种因素的影响,比如继承、配置文件、外部设置等等。为了看到实际的POM,让我们在child-a目录下运行mvn help:effective-pom。
mvn help:effective-pom
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<maxmem>512m</maxmem>
</configuration>
</plugin>
As expected, child-a has its own variation of source and target values. However, one additional surprise is that it also has the maxmem property from its parent.
正如预期的那样,child-a有自己的source和target值的变化。然而,一个额外的惊喜是,它也有来自其父辈的maxmem属性。
This means if any child property is defined, it will win, otherwise, the parent one will be used.
这意味着如果有任何子属性被定义,它将获胜,否则,将使用父属性。
3. Advanced Configuration Inheritance
3.高级配置继承
When we want to fine-tune the merging strategy, we can use attributes. These attributes are placed on the XML element that we want to control. Also, they will be inherited and will affect only the first-level children.
当我们想对合并策略进行微调时,我们可以使用属性。这些属性被放置在我们想要控制的XML元素上。而且,它们将被继承,只影响第一层的子元素。
3.1. Working with Lists
3.1.使用列表工作
In the previous example, we saw what happens if the child has a different value. Now, we’ll see the case when the child has a different list of elements. As an example, let’s look at including multiple resource directories, with the maven-resources-plugin.
在前面的例子中,我们看到了如果子代有不同的值会发生什么。现在,我们来看看子代有不同的元素列表时的情况。作为一个例子,我们来看看包括多个资源目录,用maven-resources-plugin。
As a baseline, let’s configure the parent to include resources from the parent-resources directory:
作为一个基准,让我们把parent配置为包括parent-resources目录下的资源。
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<resources>
<resource>
<directory>parent-resources</directory>
</resource>
</resources>
</configuration>
</plugin>
At this point, child-a will inherit this plugin configuration from its parent. However, let’s say we wanted to define an alternative resource directory for child-a:
在这一点上,child-a将从其父辈那里继承这个插件配置。然而,假设我们想为child-a定义一个替代的资源目录。
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<resources>
<resource>
<directory>child-a-resources</directory>
</resource>
</resources>
</configuration>
</plugin>
Now, let’s review the effective POM:
现在,让我们回顾一下有效的POM。
mvn help:effective-pom
...
<configuration>
<resources>
<resource>
<directory>child-a-resources</directory>
</resource>
</resources>
</configuration>
In this case, the entire list is overridden by the child configuration.
在这种情况下,整个列表被子配置所覆盖。
3.2. Append Parent Configuration
3.2.追加父类配置
Perhaps we want some children to use a common resource directory and also define additional ones. For this, we can append the parent configuration by using combine.children=”append” on the resources element in the parent:
也许我们想让一些子代使用一个共同的资源目录,同时也定义一些额外的资源。为此,我们可以通过在父代的资源元素上使用combine.children=”append”来追加父代的配置。
<resources combine.children="append">
<resource>
<directory>parent-resources</directory>
</resource>
</resources>
Consequently, the effective POM will contain both of them:
因此,有效的POM将包含这两点。
mvn help:effective-pom
....
<resources combine.children="append">
<resource>
<directory>parent-resources</directory>
</resource>
<resource>
<directory>child-a-resources</directory>
</resource>
</resources>
The combine attributes are not be propagated to any nested elements. So, had the resources section been a complex structure, the nested elements would be merged using the default strategy.
合并属性不会被传播到任何嵌套元素。因此,如果resources部分是一个复杂的结构,嵌套元素将使用默认策略进行合并。
3.3. Override Child Configuration
3.3.覆盖子配置
In the previous example, the child was not entirely in control of the final POM, owing to a parent combine strategy. A child can overrule the parent by adding combine.self=”override” on its resources element:
在前面的例子中,由于父方的组合策略,子方没有完全控制最终的POM。子代可以通过在其resources元素上添加combine.self=”override”来推翻父代。
<resources combine.self="override">
<resource>
<directory>child-a-resources</directory>
</resource>
</resources>
In this instance, the child regains control:
在这种情况下,孩子重新获得了控制权。
mvn help:effective-pom
...
<resources combine.self="override">
<resource>
<directory>child-a-resources</directory>
</resource>
</resources>
4. Non-Inheritable Plugins
4.不可继承的插件
The previous attributes are suitable for fine-tuning, but they’re not appropriate when the child completely disagrees with its parent.
前面的属性适合微调,但当孩子与父母完全不一致时,它们就不合适了。
To avoid a plugin being inherited at all, we can add the property <inherited>false</inherited> at the parent level:
为了避免一个插件被完全继承,我们可以在父级添加属性<inherited>false</inherited> 。
<plugin>
<inherited>false</inherited>
<groupId>org.apache.maven.plugins</groupId>
...
</plugin>
This means the plugin will be applied only for the parent and will not be propagated to its children.
这意味着该插件将只应用于父代,而不会传播到其子代。
5. Conclusion
5.总结
In this article, we saw how to override the parent plugin configuration.
在这篇文章中,我们看到了如何覆盖父插件的配置。
First, we explored the default behavior. Then we saw how a parent can define a merging policy and how a child can reject it. Finally, we saw how to mark a plugin as non-inheritable to avoid all children having to override it.
首先,我们探讨了默认行为。然后我们看到父代如何定义一个合并策略,子代如何拒绝它。最后,我们看到如何将一个插件标记为不可继承,以避免所有的子代必须覆盖它。
As always, the code is available over on GitHub.
一如既往,代码可在GitHub上获得。