Java 如何在 Spring Boot 应用程序中读取我的 META-INF/MANIFEST.MF 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32293962/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to read my META-INF/MANIFEST.MF file in a Spring Boot app?
提问by Ricardo Memoria
I'm trying to read my META-INF/MANIFEST.MF file from my Spring Boot web app (contained in a jar file).
我正在尝试从 Spring Boot Web 应用程序(包含在 jar 文件中)读取 META-INF/MANIFEST.MF 文件。
I'm trying the following code:
我正在尝试以下代码:
InputStream is = getClass().getResourceAsStream("/META-INF/MANIFEST.MF");
Properties prop = new Properties();
prop.load( is );
But apparently there is something behind the scenes in Spring Boot that a different manifest.mf is loaded (and not my own located in META-INF folder).
但显然 Spring Boot 的幕后有一些东西加载了不同的 manifest.mf(而不是我自己的位于 META-INF 文件夹中)。
Does anyone know how I can read my manifest app in my Spring Boot app?
有谁知道如何在 Spring Boot 应用程序中读取清单应用程序?
UPDATE:After some research I noticed that using the usual way to read a manifest.mf file, in a Spring Boot application this is the Jar that is being accessed
更新:经过一些研究,我注意到使用通常的方式读取 manifest.mf 文件,在 Spring Boot 应用程序中,这是正在访问的 Jar
org.springframework.boot.loader.jar.JarFile
回答by Andreas
Pretty much all jar files come with a manifest file, so your code is returning the firstfileit can find in the classpath.
几乎所有 jar 文件都带有一个清单文件,因此您的代码将返回它可以在 classpath 中找到的第一个文件。
Why would you want the manifest anyway? It's a file used by Java. Put any custom values you need somewhere else, like in a .properties
file next to you .class
file.
你为什么想要清单?它是 Java 使用的文件。将您需要的任何自定义值放在其他地方,例如在您的.properties
文件旁边的.class
文件中。
Update 2
更新 2
As mentioned in a comment below, notin the question, the real goal is the version information from the manifest. Java already supplies that information with the java.lang.Package
class.
正如下面的评论中所提到的,不是在问题中,真正的目标是清单中的版本信息。Java 已经在java.lang.Package
类中提供了这些信息。
Don't try to read the manifest yourself, even if you could find it.
不要试图自己阅读清单,即使你能找到它。
Update 1
更新 1
Note that the manifest file is nota Properties
file. It's structure is much more complex than that.
请注意,清单文件是不是一个Properties
文件。它的结构比这复杂得多。
See the example in the java documentation of the JAR File Specification.
请参阅JAR 文件规范的 java 文档中的示例。
Manifest-Version: 1.0
Created-By: 1.7.0 (Sun Microsystems Inc.)
Name: common/class1.class
SHA-256-Digest: (base64 representation of SHA-256 digest)
Name: common/class2.class
SHA1-Digest: (base64 representation of SHA1 digest)
SHA-256-Digest: (base64 representation of SHA-256 digest)
As you can see, Name
and SHA-256-Digest
occurs more than once. The Properties
class cannot handle that, since it's just a Map
and the keys have to be unique.
如您所见,Name
并且SHA-256-Digest
发生不止一次。本Properties
类无法处理,因为它只是一个Map
和键必须是唯一的。
回答by outdev
public Properties readManifest() throws IOException {
Object inputStream = this.getClass().getProtectionDomain().getCodeSource().getLocation().getContent();
JarInputStream jarInputStream = new JarInputStream((InputStream) inputStream);
Manifest manifest = jarInputStream.getManifest();
Attributes attributes = manifest.getMainAttributes();
Properties properties = new Properties();
properties.putAll(attributes);
return properties;
}
回答by abosancic
It's simple just add this
这很简单,只需添加这个
InputStream is = this.getClass().getClassLoader().getResourceAsStream("META-INF/MANIFEST.MF");
Properties prop = new Properties();
try {
prop.load( is );
} catch (IOException ex) {
Logger.getLogger(IndexController.class.getName()).log(Level.SEVERE, null, ex);
}
Working for me.
为我工作。
Note:
笔记:
getClass().getClassLoader() is important
getClass().getClassLoader() 很重要
and
和
"META-INF/MANIFEST.MF" not "/META-INF/MANIFEST.MF"
“META-INF/MANIFEST.MF”不是“/META-INF/MANIFEST.MF”
Thanks Aleksandar
谢谢亚历山大
回答by Ricardo Memoria
After testing and searching on Spring docs, I found a way to read the manifest file.
在 Spring 文档上进行测试和搜索后,我找到了一种读取清单文件的方法。
First off, Spring Boot implements its own ClassLoader that changes the way how resources are loaded. When you call getResource()
, Spring Boot will load the first resource that matches the given resource name in the list of all JARs available in the class path, and your app jar is not the first choice.
首先,Spring Boot 实现了自己的 ClassLoader,它改变了资源的加载方式。当您调用 时getResource()
,Spring Boot 将加载类路径中所有可用 JAR 列表中与给定资源名称匹配的第一个资源,并且您的应用 jar 不是首选。
So, when issuing a command like:
因此,当发出如下命令时:
getClassLoader().getResourceAsStream("/META-INF/MANIFEST.MF");
The first MANIFEST.MF file found in any Jar of the Class Path is returned. In my case, it came from a JDK jar library.
返回在类路径的任何 Jar 中找到的第一个 MANIFEST.MF 文件。就我而言,它来自 JDK jar 库。
SOLUTION:
解决方案:
I managed to get a list of all Jars loaded by the app that contains the resource "/META-INF/MANIFEST.MF" and checked if the resource came from my application jar. If so, read its MANIFEST.MF file and return to the app, like that:
我设法获取了包含资源“/META-INF/MANIFEST.MF”的应用程序加载的所有 Jars 的列表,并检查了该资源是否来自我的应用程序 jar。如果是这样,请阅读其 MANIFEST.MF 文件并返回到应用程序,如下所示:
private Manifest getManifest() {
// get the full name of the application manifest file
String appManifestFileName = this.getClass().getProtectionDomain().getCodeSource().getLocation().toString() + JarFile.MANIFEST_NAME;
Enumeration resEnum;
try {
// get a list of all manifest files found in the jars loaded by the app
resEnum = Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME);
while (resEnum.hasMoreElements()) {
try {
URL url = (URL)resEnum.nextElement();
// is the app manifest file?
if (url.toString().equals(appManifestFileName)) {
// open the manifest
InputStream is = url.openStream();
if (is != null) {
// read the manifest and return it to the application
Manifest manifest = new Manifest(is);
return manifest;
}
}
}
catch (Exception e) {
// Silently ignore wrong manifests on classpath?
}
}
} catch (IOException e1) {
// Silently ignore wrong manifests on classpath?
}
return null;
}
This method will return all data from a manifest.mf file inside a Manifest object.
此方法将从 Manifest 对象内的 manifest.mf 文件返回所有数据。
I borrowed part of the solution from reading MANIFEST.MF file from jar file using JAVA
我从使用 JAVA 从 jar 文件中读取 MANIFEST.MF 文件借用了部分解决方案
回答by samsong8610
I use java.lang.Packageto read the Implementation-Version
attribute in spring boot from the manifest.
我使用java.lang.PackageImplementation-Version
从清单中读取spring boot 中的属性。
String version = Application.class.getPackage().getImplementationVersion();
The Implementation-Version
attribute should be configured in build.gradle
该Implementation-Version
属性应配置在build.gradle
jar {
baseName = "my-app"
version = "0.0.1"
manifest {
attributes("Implementation-Version": version)
}
}
回答by usethe4ce
I have it exploiting Spring's resource resolution:
我有它利用 Spring 的资源解析:
@Service
public class ManifestService {
protected String ciBuild;
public String getCiBuild() { return ciBuild; }
@Value("${manifest.basename:/META-INF/MANIFEST.MF}")
protected void setManifestBasename(Resource resource) {
if (!resource.exists()) return;
try (final InputStream stream = resource.getInputStream()) {
final Manifest manifest = new Manifest(stream);
ciBuild = manifest.getMainAttributes().getValue("CI-Build");
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Here we're getting CI-Build
, and you can easily extend the example to load other attributes.
在这里,我们得到了CI-Build
,您可以轻松地扩展示例以加载其他属性。
回答by Ihor M.
try {
final JarFile jarFile = (JarFile) this.getClass().getProtectionDomain().getCodeSource().getLocation().getContent();
final Manifest manifest = jarFile.getManifest();
final Map<Object, Object> manifestProps = manifest.getMainAttributes().entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));
...
} catch (final IOException e) {
LOG.error("Unable to read MANIFEST.MF", e);
...
}
This will work only if you launch your app via java -jar
command, it won't work if one create an integration test.
这仅在您通过java -jar
命令启动应用程序时才有效,如果创建集成测试则无效。