当您从命令行启动 Maven 时,它会经历多个阶段。这是对这些阶段的伪描述,我有意简化确切的顺序(冒着说出稍微不正确/乱序的事情的风险),以便您可以了解为什么您尝试做的事情行不通。
首先它解析你的命令行,使用命令行定义的任何属性-Dname=value
都被注入到MavenSession
检查反应堆定义命令行选项以确定要构建的项目列表(也称为反应堆)应该是什么。-N
表示仅构建 root pom.xml
,-pl
允许指定要构建的模块列表,-am
并-amd
允许分别从-pl
. Maven 目前还没有解析任何pom.xml
文件。
分析-P
配置文件激活规则以查看要激活的配置文件。
现在 Maven 有足够的知识开始解析pom.xml
文件了。它首先加载和解析 root pom.xml
,即当前目录中的那个(或者如果你指定了一个替代pom.xml
项-f
)。这个初始解析只是专注于找出要构建的项目列表。仅在可能影响<modules>
可用列表的情况下才考虑配置文件激活。中的 Group Id、Artifact Id、Version 和 Packaging 坐标pom.xml
不能包含属性,因为此时还没有对 中的属性进行解析pom.xml
。(细心的读者也会看到,这也解释了为什么您不能根据pom.xml
,因为在这个阶段只解析了系统属性)
一旦项目集得到验证,Maven 现在会对这些pom.xml
文件进行更多解析,以构建构建扩展列表(如果有)和插件列表。在这个阶段,解析需要对<properties>
每个项目中的 进行评估,因此这是对这些进行评估并“注入”到有效模型中的时候。因此,您可以使用系统属性和pom 属性来定义 (xpath) /project/build/extensions
、/project/build/pluginManagement/plugins/plugin
、/project/build/pluginManagement/plugins/plugin/dependencies
和./project/build/plugins/plugin
/project/build/plugins/plugin/dependencies
现在 Maven 开始解析命令行中指定的目标和阶段列表。评估部分指定的目标以匹配插件列表。对于将执行插件目标的所有项目,匹配必须是唯一的(即,如果它是聚合器目标,则匹配仅在根处需要,但对于所有其他“正常”目标,插件短名称必须是所有项目都使用相同的插件)。生命周期阶段必须来自默认生命周期之一,或来自构建扩展中定义的生命周期。
从解析的目标和阶段列表中,Maven 构建构建计划,即它将在哪些项目上以什么顺序执行。为了做到这一点,Maven 必须解析在 reactor 项目pom.xml
文件中定义的项目依赖项列表。这是因为依赖关系可能由反应器内的另一个项目产生,从而强制项目执行的顺序。因此,您可以使用系统属性和 pom 属性来定义 (xpath) 中的坐标和其他依赖项/project/dependencyManagement/dependencies/dependency
,/project/dependencies/dependency
但请注意,此时尚未执行任何插件。
现在 Maven 有了构建计划,它开始按照它构建的顺序执行该计划。如果 CLI 上的第一个目标/阶段是一个目标,那么将调用该目标。如果第一个目标/阶段是默认构建生命周期中的一个阶段,那么 Maven 将从该initialize
阶段开始并执行绑定到该阶段的所有插件......以类似的方式沿着阶段列表继续,然后是项目列表. 另请注意,initialize
阶段仅作为默认构建生命周期的一部分执行。它不会在默认的干净或默认站点生命周期上执行,也不会在任何自定义生命周期上执行。(细心的读者会得出结论,这突出了该问题所尝试的技术的另一个问题)。注意:请记住,聚合器目标在反应器中形成“中断”,因此如果您要求 Maven 在clean package foo:bar site
哪里运行foo:bar
聚合器 mojo 目标,那么clean package
将针对反应器中的所有项目运行,然后foo:bar
将针对根运行,然后site
将针对反应堆中的所有项目运行。换句话说,构建计划将采用最长连续运行的非聚合器目标和阶段,除以最长连续运行的聚合器目标。
在调用每个 mojo(即绑定到阶段或直接从命令行指定的目标)之前,Maven 会评估该mojopom.xml
的有效性<configuration>
。此时,Maven 已经可以使用系统属性、在 pom 中指定的属性以及MavenSession
由先前执行的 mojos注入的任何属性。因此,<configuration>
可以引用这些属性中的任何一个......
在旁边
现在有一个警告......如果你说 set (xpath ) to/project/build/directory
然后${some-property-i-will-set-via-a-mojo}
从你的.字面值,它是in 的类型,所以你实际上会发生的是. 如果您要注入的字段是 type ,则不需要进行类型转换,因此该值将直接注入,并且不会发生任何属性替换。<configuration>
/project/build/directory
pom.xml
${project.build.directory}
${some-property-i-will-set-via-a-mojo}
java.io.File
MavenProject
new File(project.getBaseDir(),"${some-property-i-will-set-via-a-mojo}")
<configuration>
File
还有其他边缘情况,例如上面概述的情况,但通常属性替换将使用这些部分中的“mojo 注入”属性(例如Mojo 的 Properties Maven Plugin提供的那些)<configuration>
。它不会在这些部分之外工作。
所以这里是斯蒂芬对不同属性类型的快速经验法则:
系统属性
这些工作无处不在......但是非常危险,/project/(parent/)?/(groupId|artifactId|version|packaging)
因为当项目作为传递依赖项被拉入时,您无法控制将定义哪些系统属性。使用${...}
内部膨胀/project/(parent/)?/(groupId|artifactId|version|packaging)
应该被认为等同于以 200 公里/小时的速度驾驶汽车,并用一个从方向盘突出的 30 厘米(12 英寸)金属钉代替安全气囊......哦,没有安全带......你刚刚有 10 个单位的酒精和两行可卡因。
pom.xml
属性(和settings.xml
属性)
这些在大多数地方都有效,但在内部永远不可用/project/(parent/)?/(groupId|artifactId|version|packaging)
(因为在评估这些字段时它们尚未被解析)并且不可用于考虑活动配置文件(再次因为在评估配置文件激活时它们尚未被解析)
Mojo 注入属性
这些工作在<configuration>
部分内,并且可能(由于注入的 MojoString
参数的递归插值)在间接使用时工作,但考虑到所涉及的不确定性,建议将它们的使用限制在<configuration>
插件和报告部分。
最后一件事
想想当你的项目被列为依赖项时会发生什么。如果您已通过使用 mojo 从磁盘上的文件中提取依赖项来指定其依赖项.properties
,则当您的依赖项已从 Maven 存储库中提取时,Maven 无法复制该依赖项。所以 Maven 将无法确定依赖关系。因此它永远无法工作。
您可以做的是使用外部系统(例如 ANT)pom.xml
从模板生成,并将版本替换到该文件中。然后使用实例化的模板进行构建。