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

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

250940 次浏览

假设你正在使用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指定一个概要文件时,它可以启用属性,然后可以在你的构建中显示。

打包的工件包含一个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()

我发现这个方法更简单。

使用这个库可以获得简单的解决方案。向清单中添加您需要的任何内容,然后按字符串查询。

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

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

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

getClass().getPackage().getImplementationVersion()

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

为了补充@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@

公认的答案可能是在应用程序静态< em > < / em >中获取版本号的最佳和最稳定的方法,但实际上并没有回答最初的问题:如何从pom.xml中检索工件的版本号?因此,我想提供一个替代方案,显示如何在运行时动态< em > < / em >执行此操作:

您可以使用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

为了回答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());
}
}
    <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()获取Version

PS别忘了补充:

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

有时,当编写与项目版本相关的脚本时,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

参考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();

当使用spring引导时,这个链接可能有用: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;

步骤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访问Build属性。在我们的例子中,我们创建了一个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);
}
}

我希望这能有所帮助

因为我记得这个经常被提及的问题,在几年前有了回答之后,显示了一个动态版本,实际上是动态访问Maven POM信息(例如,也在测试期间),今天我发现了一个类似的问题,涉及从另一个模块B访问模块a的Maven信息。

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

我在白天的工作中也遇到了同样的问题。尽管许多答案将有助于找到特定工件的版本,但我们需要获得不是应用程序直接依赖的模块/jar的版本。类路径在应用程序启动时由多个模块组装而成,主应用程序模块不知道后来添加了多少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);

查找groupId 开始于 de.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文件中,或者可能添加到公司的master 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项目上添加一个新问题。

执照

所有的源代码都是开源的,甚至可以免费用于商业产品(MIT许可证)。

如果你使用Spring和Maven,这非常简单,不需要配置。 根据使用Maven的自动属性扩展官方文档,您可以通过使用资源过滤自动扩展Maven项目的属性。如果你使用spring-boot-starter-parent,你就可以用@.引用Maven的“项目属性”。

. @占位符,示例如下
project.version=@project.version@
project.artifactId=@project.artifactId@

你可以在任何类中使用@Value注释来检索它:

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

我希望这能有所帮助!

接受的答案在第2步中为我工作过一次,我将${project.version}改为${pom.version}