繁体   English   中英

在代码中从 maven pom.xml 中检索版本

[英]Retrieve version from maven pom.xml in code

从代码中的 Maven 的 pom.xml 检索版本号的最简单方法是什么,即以编程方式?

假设您使用的是 Java,您可以:

  1. 在(最常见的)您的src/main/resources目录中创建一个.properties文件(但在第 4 步中,您可以告诉它在其他地方查找)。

  2. 使用项目版本的标准 Maven 属性在.properties文件中设置某些属性的值:

     foo.bar=${project.version}
  3. 在您的 Java 代码中,将属性文件中的值作为类路径中的资源加载(谷歌有关如何执行此操作的大量示例,但这里是初学者的示例)。

  4. 在 Maven 中,启用资源过滤。 这将导致 Maven 将该文件复制到您的输出类中,并在该复制期间翻译资源,解释属性。 你可以在这里找到一些信息但你大多只是在你的 pom 中这样做:

     <build> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> </build>

您还可以访问其他标准属性,例如project.nameproject.description ,甚至是您放入 pom <properties>任意属性等。资源过滤与 Maven 配置文件相结合,可以在构建时为您提供可变的构建行为。 当您在运行时使用-PmyProfile指定配置文件时,它可以启用随后可以显示在您的构建中的属性。

接受的答案可能是将版本号静态地获取到应用程序中的最佳和最稳定的方法,但实际上并没有回答原始问题:如何从 pom.xml 检索工件的版本号? 因此,我想提供一种替代方法,展示如何在运行时动态执行此操作:

您可以使用 Maven 本身。 更准确地说,您可以使用 Maven 库。

<dependency>
  <groupId>org.apache.maven</groupId>
  <artifactId>maven-model</artifactId>
  <version>3.3.9</version>
</dependency>

然后在 Java 中做这样的事情:

package de.scrum_master.app;

import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import java.io.FileReader;
import java.io.IOException;

public class Application {
    public static void main(String[] args) throws IOException, XmlPullParserException {
        MavenXpp3Reader reader = new MavenXpp3Reader();
        Model model = reader.read(new FileReader("pom.xml"));
        System.out.println(model.getId());
        System.out.println(model.getGroupId());
        System.out.println(model.getArtifactId());
        System.out.println(model.getVersion());
    }
}

控制台日志如下:

de.scrum-master.stackoverflow:my-artifact:jar:1.0-SNAPSHOT
de.scrum-master.stackoverflow
my-artifact
1.0-SNAPSHOT

2017年 10 月 31 日更新:为了回答 Simon Sobisch 的后续问题,我对示例进行了如下修改:

package de.scrum_master.app;

import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Application {
  public static void main(String[] args) throws IOException, XmlPullParserException {
    MavenXpp3Reader reader = new MavenXpp3Reader();
    Model model;
    if ((new File("pom.xml")).exists())
      model = reader.read(new FileReader("pom.xml"));
    else
      model = reader.read(
        new InputStreamReader(
          Application.class.getResourceAsStream(
            "/META-INF/maven/de.scrum-master.stackoverflow/aspectj-introduce-method/pom.xml"
          )
        )
      );
    System.out.println(model.getId());
    System.out.println(model.getGroupId());
    System.out.println(model.getArtifactId());
    System.out.println(model.getVersion());
  }
}

打包的工件包含一个META-INF/maven/${groupId}/${artifactId}/pom.properties文件,其内容如下所示:

#Generated by Maven
#Sun Feb 21 23:38:24 GMT 2010
version=2.5
groupId=commons-lang
artifactId=commons-lang

许多应用程序使用此文件在运行时读取应用程序/jar 版本,需要零设置。

上述方法的唯一问题是这个文件(当前)是在package阶段生成的,因此在测试等期间不会出现(有一个 Jira 问题可以改变这一点,请参阅MJAR-76 )。 如果这对您来说是个问题,那么 Alex 描述的方法就是您要走的路。

还有使用 Maven 显示应用程序版本号的简单方法中描述的方法:

将此添加到 pom.xml

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>test.App</mainClass>
            <addDefaultImplementationEntries>
              true
            </addDefaultImplementationEntries>
          </manifest>
        </archive>
      </configuration>
    </plugin>
  </plugins>
</build>

然后使用这个:

App.class.getPackage().getImplementationVersion()

我发现这种方法更简单。

如果使用 jar 或 war 等 mvn 包装,请使用:

getClass().getPackage().getImplementationVersion()

它读取存档中生成的 META-INF/MANIFEST.MF(设置为 pom.xml 的版本)的属性“Implementation-Version”。

为了补充@kieste 发布的内容,如果您使用 Spring-boot,我认为这是在您的代码中提供 Maven 构建信息的最佳方式: http ://docs.spring.io/spring-boot/ 上的文档docs/current/reference/htmlsingle/#production-ready-application-info非常有用。

您只需要激活执行器,并在application.propertiesapplication.yml添加您需要的属性

Automatic property expansion using Maven

You can automatically expand info properties from the Maven project using resource filtering. If you use the spring-boot-starter-parent you can then refer to your Maven ‘project properties’ via @..@ placeholders, e.g.

project.artifactId=myproject
project.name=Demo
project.version=X.X.X.X
project.description=Demo project for info endpoint
info.build.artifact=@project.artifactId@
info.build.name=@project.name@
info.build.description=@project.description@
info.build.version=@project.version@

使用 spring boot 时,此链接可能有用: https : //docs.spring.io/spring-boot/docs/2.3.x/reference/html/howto.html#howto-properties-and-configuration

使用 spring-boot-starter-parent,您只需将以下内容添加到您的应用程序配置文件中:

# get values from pom.xml
pom.version=@project.version@

之后,该值可用,如下所示:

@Value("${pom.version}")
private String pomVersion;

使用这个库来简化一个简单的解决方案。 将您需要的任何内容添加到清单中,然后按字符串查询。

 System.out.println("JAR was created by " + Manifests.read("Created-By"));

http://manifests.jcabi.com/index.html

有时,在编写与项目版本相关的脚本时,Maven 命令行就足够了,例如通过 URL 从存储库中检索工件:

mvn help:evaluate -Dexpression=project.version -q -DforceStdout

用法示例:

VERSION=$( mvn help:evaluate -Dexpression=project.version -q -DforceStdout )
ARTIFACT_ID=$( mvn help:evaluate -Dexpression=project.artifactId -q -DforceStdout )
GROUP_ID_URL=$( mvn help:evaluate -Dexpression=project.groupId -q -DforceStdout | sed -e 's#\.#/#g' )
curl -f -S -O http://REPO-URL/mvn-repos/${GROUP_ID_URL}/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.jar
    <build>
            <finalName>${project.artifactId}-${project.version}</finalName>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-war-plugin</artifactId>
                        <version>3.2.2</version>
                        <configuration>
                            <failOnMissingWebXml>false</failOnMissingWebXml>
                            <archive>
                                <manifest>
                                    <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                                    <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                                </manifest>
                            </archive>
                        </configuration>
                    </plugin>
                 </plugins>
            </pluginManagement>
</build>

使用this.getClass().getPackage().getImplementationVersion()获取版本

PS不要忘记添加:

<manifest>
    <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
    <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>

我在白天的工作中遇到了同样的问题。 尽管许多答案将有助于找到特定工件的版本,但我们需要获取不是应用程序直接依赖项的模块/jar 的版本。 classpath是应用启动时由多个模块组装而成的,主应用模块不知道后面添加了多少jar。

这就是为什么我想出了一个不同的解决方案,它可能比从 jar 文件读取 XML 或属性更优雅一些。

想法

  1. 使用 Java 服务加载器方法能够在以后添加尽可能多的组件/工件,这些组件/工件可以在运行时贡献自己的版本。 创建一个非常轻量级的库,只需几行代码即可读取、查找、过滤和排序类路径上的所有工件版本。
  2. 创建一个 maven 源代码生成器插件,在编译时为每个模块生成服务实现,在每个 jar 中打包一个非常简单的服务。

解决方案

解决方案的第一部分是artifact-version-service库,现在可以在githubMavenCentral上找到它。 它涵盖了服务定义和一些在运行时获取工件版本的方法。

第二部分是artifact-version-maven-plugin ,它也可以在githubMavenCentral上找到。 它用于拥有一个轻松的生成器,为每个工件实现服务定义。

例子

获取所有带有坐标的模块

不再读取 jar 清单,只需一个简单的方法调用:

// iterate list of artifact dependencies
for (Artifact artifact : ArtifactVersionCollector.collectArtifacts()) {
    // print simple artifact string example
    System.out.println("artifact = " + artifact);
}

返回一组排序的工件。 要修改排序顺序,请提供自定义比较器:

new ArtifactVersionCollector(Comparator.comparing(Artifact::getVersion)).collect();

这样,工件列表按版本号排序返回。

查找特定工件

ArtifactVersionCollector.findArtifact("de.westemeyer", "artifact-version-service");

获取特定工件的版本详细信息。

查找具有匹配 groupId 的工件

使用 groupId de.westemeyer查找所有工件(完全匹配):

ArtifactVersionCollector.findArtifactsByGroupId("de.westemeyer", true);

查找 groupIdde.westemeyer开头的所有工件:

ArtifactVersionCollector.findArtifactsByGroupId("de.westemeyer", false);

按版本号排序结果:

new ArtifactVersionCollector(Comparator.comparing(Artifact::getVersion)).artifactsByGroupId("de.", false);

对工件列表实施自定义操作

通过提供一个 lambda,第一个例子可以这样实现:

ArtifactVersionCollector.iterateArtifacts(a -> {
    System.out.println(a);
    return false;
});

安装

将这两个标签添加到所有pom.xml文件中,或者添加到某个公司的主 pom 中:

<build>
  <plugins>
    <plugin>
      <groupId>de.westemeyer</groupId>
      <artifactId>artifact-version-maven-plugin</artifactId>
      <version>1.1.0</version>
      <executions>
        <execution>
          <goals>
            <goal>generate-service</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

<dependencies>
  <dependency>
    <groupId>de.westemeyer</groupId>
    <artifactId>artifact-version-service</artifactId>
    <version>1.1.0</version>
  </dependency>
</dependencies>

回馈

如果有人可以尝试一下解决方案,那就太好了。 获得有关您认为该解决方案是否符合您的需求的反馈会更好。 因此,如果您有任何建议、功能请求、问题,请不要犹豫,在任何 github 项目上添加新问题。

执照

所有源代码都是开源的,甚至可以免费用于商业产品(麻省理工学院许可证)。

第 1 步:如果您使用 Spring Boot,您的 pom.xml 应该已经包含spring-boot-maven-plugin 您只需要添加以下配置。

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>build-info</id>
            <goals>
                <goal>build-info</goal>
            </goals>
        </execution>
    </executions>
</plugin>

它指示插件也执行 build-info 目标,默认情况下不运行。 这会生成有关您的应用程序的构建元数据,其中包括工件版本、构建时间等。

步骤 2:使用 buildProperties bean 访问构建属性。 在我们的例子中,我们创建了一个 restResource 来访问我们的 webapp 中的这个构建信息

@RestController
@RequestMapping("/api")
public class BuildInfoResource {
    @Autowired
    private BuildProperties buildProperties;

    
    @GetMapping("/build-info")
    public ResponseEntity<Map<String, Object>> getBuildInfo() {
        Map<String, String> buildInfo = new HashMap();
        buildInfo.put("appName", buildProperties.getName());
        buildInfo.put("appArtifactId", buildProperties.getArtifact());
        buildInfo.put("appVersion", buildProperties.getVersion());
        buildInfo.put("appBuildDateTime", buildProperties.getTime());
        return ResponseEntity.ok().body(buldInfo);
    }
}

我希望这会有所帮助

参考ketankk的回答

不幸的是,添加这个会影响我的应用程序处理资源的方式:

<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>   
</build>

但是在 maven-assemble-plugin 的 < manifest > 标签中使用它可以解决问题:

<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>

所以我能够使用

String version = getClass().getPackage().getImplementationVersion();

前言:因为我记得几年前回答了这个经常被提及的问题,展示了一个动态版本实际动态访问Maven POM信息(例如也在测试期间),今天我发现了一个类似的问题,涉及访问模块A的Maven信息来自另一个模块 B.

我想了一会儿,自发地有了使用特殊注释的想法,将其应用于package-info.java的包声明。 我还在 GitHub 上创建了一个多模块示例项目。 我不想重复整个答案,所以请参阅本答案中的解决方案 B。 Maven 设置涉及Templating Maven Plugin ,但也可以使用资源过滤和通过 Build Helper Maven 将生成的源目录添加到构建的组合以更详细的方式解决。 我想避免这种情况,所以我只是使用了模板 Maven。

如果您将 Spring 与 Maven 一起使用,则非常简单,无需配置。 根据“Automatic Property Expansion Using Maven”官方文档,您可以使用资源过滤从 Maven 项目中自动扩展属性。 如果您使用 spring-boot-starter-parent,则可以使用 @..@ 占位符引用您的 Maven '项目属性',如下例所示:

project.version=@project.version@
project.artifactId=@project.artifactId@

您可以在任何 class 中使用 @Value 注释检索它:

@Value("${project.artifactId}@${project.version}")
private String RELEASE;

我希望这有帮助!

在步骤 #2 中接受的答案对我有用一次我将${project.version}更改为${pom.version}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM