从 Maven 中的 POM 文件中读取属性文件

Posted

技术标签:

【中文标题】从 Maven 中的 POM 文件中读取属性文件【英文标题】:Reading Properties file from POM file in Maven 【发布时间】:2013-01-21 10:08:33 【问题描述】:

为什么这不起作用?如何从属性文件中选择版本号。

读取 pom.xml 中的属性

<project>
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>properties-maven-plugin</artifactId>
        <version>1.0</version>
        <executions>
          <execution>
            <phase>initialize</phase>
            <goals>
              <goal>read-project-properties</goal>
            </goals>
          </execution>
          <configuration>
            <files>
              <file>dev.properties</file>
            </files>
          </configuration>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

在 dev.properties 中

org.aspectj.aspectjrt.version=1.6.11

pom.xml 中的依赖关系

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>$org.aspectj.aspectjrt.version</version>
        </dependency>

错误:依赖项必须是有效版本

【问题讨论】:

为什么不指定版本?来自 pom 文件? 【参考方案1】:

当您从命令行启动 Maven 时,它会经历多个阶段。这是对这些阶段的伪描述,我有意简化确切的顺序(可能会说一些稍微不正确/无序的事情),以便您了解为什么您尝试做的事情行不通。

    首先它解析你的命令行,在命令行上使用-Dname=value定义的任何属性都被注入MavenSession

    检查反应堆定义命令行选项以确定要构建的项目列表(也称为反应堆)应该是什么。 -N 表示仅构建根 pom.xml-pl 允许指定要构建的模块列表,-am-amd 允许分别从 -pl 指定的模块添加上游或下游模块。 Maven 目前还没有解析任何pom.xml 文件。

    解析-P 配置文件激活规则以查看要激活哪些配置文件。

    现在 Maven 有足够的知识开始解析 pom.xml 文件。它首先加载和解析根pom.xml,即当前目录中的那个(或者如果你用-f指定了一个替代pom.xml,那么那个)。这个初始解析只是专注于找出要构建的项目列表。仅在可能影响可用&lt;modules&gt; 列表的情况下才考虑配置文件激活。 pom.xml 中的 Group Id、Artifact Id、Version 和 Packaging 坐标不能包含属性,因为此时尚未对 pom.xml 中的属性进行解析。 (细心的读者也会看到,这也解释了为什么您不能根据 pom.xml 中的属性激活配置文件,因为在此阶段只解析了系统属性)

    一旦项目集得到验证,Maven 现在会对这些pom.xml 文件进行更多解析,以构建构建扩展列表(如果有)和插件列表。在这个阶段,解析需要评估每个项目中的&lt;properties&gt;,因此这是对这些进行评估并“注入”到有效模型中的时候。因此,您可以使用系统属性和 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 必须解析在反应器项目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 将针对reactor,然后 foo:bar 将针对 root 运行,然后 site 将针对 reactor 中的所有项目运行。换句话说,构建计划将采用最长连续运行的非聚合器目标和阶段,除以最长连续运行的聚合器目标。

    在调用每个 mojo(即绑定到阶段或直接从命令行指定的目标)之前,Maven 会评估 pom.xml 以获得该 mojo 的有效 &lt;configuration&gt;。此时 Maven 已经可以使用系统属性、在 pom 中指定的属性任何由先前执行的 mojos 注入到MavenSession 中的属性。因此&lt;configuration&gt; 可以引用这些属性中的任何一个......

    一边

    现在有一个警告...如果您将 (xpath) /project/build/directory 设置为 $some-property-i-will-set-via-a-mojo 然后从您的 &lt;configuration&gt; 中引用它,那么可悲的消息是 (xpath) /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")。如果您要注入的 &lt;configuration&gt; 字段的类型为 File,则不需要进行类型转换,因此该值将直接注入,并且不会发生任何属性替换。

    还有其他边缘情况,如上面概述的情况,但一般属性替换将适用于&lt;configuration&gt; 中的“mojo 注入”属性(例如由Mojo's Properties Maven Plugin 提供的那些)部分。它不会在这些部分之外工作。

以下是 Stephen 针对不同属性类型的快速经验法则:

系统属性

这些工作无处不在...但在/project/(parent/)?/(groupId|artifactId|version|packaging)非常危险,因为当项目作为传递依赖项引入时,您无法控制将定义哪些系统属性。在/project/(parent/)?/(groupId|artifactId|version|packaging) 内使用$... 扩展应被视为等同于以200kph 的速度驾驶汽车,并在方向盘上突出一个30 厘米(12 英寸)的金属钉代替安全气囊......哦,没有安全带...... . 而你刚刚喝了 10 个单位的酒精和两行可卡因。

pom.xml 属性(和settings.xml 属性)

这些在大多数地方都有效,但在 /project/(parent/)?/(groupId|artifactId|version|packaging) 中永远不可用(因为在评估这些字段时它们还没有被解析)并且不能用于考虑活动配置文件(同样因为它们没有被解析时正在评估配置文件激活)

Mojo 注入属性

这些工作在 &lt;configuration&gt; 部分中,并且在间接使用时可能(由于注入的 Mojo String 参数的递归插值)工作,但考虑到所涉及的不确定性,建议将它们的使用限制在 &lt;configuration&gt; 部分仅插件和报告。

最后一件事

想想当您的项目被列为依赖项时会发生什么。如果您已通过使用 mojo 从磁盘上的 .properties 文件中提取它们来指定其依赖项,则当您的依赖项已从 Maven 存储库中提取时,Maven 无法复制该依赖项。所以 Maven 将无法确定依赖关系。因此它永远无法工作。

您可以做的是使用外部系统(例如 ANT)从模板生成pom.xml,并将版本替换到该文件中。然后使用实例化的模板进行构建。

【讨论】:

这个解释太好了! +100 我不同意,我在验证阶段使用 buildnumber-maven-plugin,它生成的版本号为 $buildNumber,它正在工作并生成文件名中包含 buildnumber 的 jar 文件。 你会发现推送到本地/远程仓库时无法保留jar名。 target 目录中的 jar 名称可能会受到影响,因为它是在 package 阶段评估的……但它仅适用于在生命周期启动后评估的内容。 GAV 坐标在生命周期启动之前 进行评估。在多模块构建中,您会看到您可能认为您在 GAV 中使用属性替换的任何东西实际上都被破坏了 我从未如此完全满意,但对答案如此彻底失望;)【参考方案2】:

properties(dev.properties) 文件用于构建作业。

<files>
   <file>dev.properties</file>
</files>

对于依赖项,您需要在 pom.xml 文件中添加如下内容。

<properties>

<org.aspectj.aspectjrt.version>1.6.11</org.aspectj.aspectjrt.version>
</properties>

【讨论】:

如何让pom文件从属性文件中选择版本号?

以上是关于从 Maven 中的 POM 文件中读取属性文件的主要内容,如果未能解决你的问题,请参考以下文章

maven - 从属性文件中读取版本号

有没有办法从 text.file 读取文本并将其设置为 pom.xml maven 中的 maven 属性?

从Maven pom.xml更新sonar-project.properties文件中的特定属性?

maven:从属性文件中读取 sonar.login

有没有办法将 POM 参数/属性传递给 TestNG XML 文件?

Maven 配置文件属性不会覆盖弹簧配置中的值