【发布时间】:2011-04-11 11:29:58
【问题描述】:
在代码中(即以编程方式)从 maven 的 pom.xml 中检索版本号的最简单方法是什么?
【问题讨论】:
在代码中(即以编程方式)从 maven 的 pom.xml 中检索版本号的最简单方法是什么?
【问题讨论】:
假设您使用的是 Java,您可以:
在(最常见的)src/main/resources 目录中创建一个.properties 文件(但在第 4 步中,您可以告诉它到别处查找)。
使用项目版本的标准 Maven 属性在 .properties 文件中设置某些属性的值:
foo.bar=${project.version}
在您的 Java 代码中,将属性文件中的值作为类路径中的资源加载(谷歌有很多关于如何执行此操作的示例,但 here's an example for starters)。
在 Maven 中,启用资源过滤。这将导致 Maven 将该文件复制到您的输出类中,并在该复制期间翻译资源,解释属性。你可以找到一些信息 here 但你大多只是在你的 pom 中这样做:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
您还可以访问其他标准属性,例如 project.name、project.description,甚至是您放入 pom <properties> 等的任意属性。资源过滤与 Maven 配置文件相结合,可以在以下位置为您提供可变的构建行为建造时间。当您在运行时使用 -PmyProfile 指定配置文件时,可以启用随后可以显示在您的构建中的属性。
【讨论】:
src/main/resources 上使用过滤,因为这可能会处理此目录中的所有文件,包括二进制文件。为了避免不可预知的行为,最好在src/main/resources-filtered 目录as suggested here 上进行过滤。无论如何,谢谢你的好把戏!
@project.version@而不是${project.version}
接受的答案可能是静态将版本号放入应用程序的最佳和最稳定的方法,但实际上并没有回答原始问题:如何检索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());
}
}
【讨论】:
packaged jar 启动时却没有(依赖类未集成)并且没有使用 maven-assembly-plugin jar-with-dependencies 打包时工作我得到一个 java.io.FileNotFoundException: pom.xml(它在最终的 jar 中为 META-INF/maven/my.package/myapp/pom.xml) - 任何提示如何解决这个问题?
打包的工件包含一个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 描述的方法就是要走的路。
【讨论】:
还有Easy way to display your apps version number using 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()
我发现这种方法更简单。
【讨论】:
getImplementationVersion() 的值为 null。 (maven 3.0.4 版)
.war 工件,记得使用maven-war-plugin 而不是maven-jar-plugin
getImplementationVersion() 返回 null)。跨度>
如果使用 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.properties 或application.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@
【讨论】:
有时,在编写与项目版本相关的脚本时,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
【讨论】:
使用 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"));
【讨论】:
<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 或属性更优雅一些。
解决方案的第一部分是artifact-version-service 库,现在可以在github 和MavenCentral 上找到它。它涵盖了服务定义和一些在运行时获取工件版本的方法。
第二部分是artifact-version-maven-plugin,也可以在github 和MavenCentral 上找到。它用于让生成器轻松实现每个工件的服务定义。
不再需要读取jar manifest,只需一个简单的方法调用:
// 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 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 文件中,或者添加到某处的公司主 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 许可证)。
【讨论】:
第 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);
}
}
我希望这会有所帮助
【讨论】:
不幸的是,添加此内容会影响我的应用程序处理资源的方式:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
但是在 maven-assemble-plugin 的
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
所以我可以使用
String version = getClass().getPackage().getImplementationVersion();
【讨论】:
前言: 因为我记得几年前answered 之后经常提到的这个问题,显示了一个动态版本实际上动态访问 Maven POM 信息(例如在测试期间),今天我发现了一个similar question,它涉及从另一个模块 B 访问模块 A 的 Maven 信息。
想了想,不由自主地产生了使用特殊注解的想法,将其应用到package-info.java中的包声明中。我还在 GitHub 上创建了一个多模块示例项目。我不想重复整个答案,所以请参阅this answer 中的解决方案 B。 Maven 设置涉及模板化 Maven 插件,但也可以使用资源过滤和通过 Build Helper Maven 将生成的源目录添加到构建的组合以更详细的方式解决。我想避免这种情况,所以我只是使用了 Maven 模板。
【讨论】: