简体   繁体   English

如何在Spring Boot应用程序中读取我的META-INF / MANIFEST.MF文件?

[英]How to read my META-INF/MANIFEST.MF file in a Spring Boot app?

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

I use java.lang.Package to read the Implementation-Version attribute in spring boot from the manifest. 我使用java.lang.Package从清单中读取spring boot中的Implementation-Version属性。

String version = Application.class.getPackage().getImplementationVersion();

The Implementation-Version attribute should be configured in build.gradle 应在build.gradle配置Implementation-Version属性

jar {
    baseName = "my-app"
    version =  "0.0.1"
    manifest {
        attributes("Implementation-Version": version)
    }
}

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 谢谢Aleksandar

Pretty much all jar files come with a manifest file, so your code is returning the first file it can find in the classpath . 几乎所有jar文件都带有清单文件,因此您的代码将返回它可以在类路径中找到的第一个文件

Why would you want the manifest anyway? 为什么你还想要清单呢? It's a file used by Java. 它是Java使用的文件。 Put any custom values you need somewhere else, like in a .properties file next to you .class file. 将您需要的任何自定义值放在其他位置,例如在.class文件旁边的.properties文件中。

Update 2 更新2

As mentioned in a comment below, not in 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 not a Properties file. 请注意,清单文件不是 Properties文件。 It's structure is much more complex than that. 它的结构要复杂得多。

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. 如您所见, NameSHA-256-Digest不止一次出现。 The Properties class cannot handle that, since it's just a Map and the keys have to be unique. Properties类无法处理,因为它只是一个Map ,键必须是唯一的。

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. 首先,Spring Boot实现了自己的ClassLoader,它改变了资源的加载方式。 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. 当您调用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. 返回在类路径的任何Jar中找到的第一个MANIFEST.MF文件。 In my case, it came from a JDK jar library. 就我而言,它来自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. 我设法得到包含资源“/META-INF/MANIFEST.MF”的应用程序加载的所有Jars的列表,并检查资源是否来自我的应用程序jar。 If so, read its MANIFEST.MF file and return to the app, like that: 如果是这样,请阅读其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文件中借用了部分解决方案

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 ,您可以轻松扩展示例以加载其他属性。

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;
}
    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命令启动应用程序时才有效,如果创建集成测试,它将无法工作。

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

相关问题 如何从* .war / META-INF / MANIFEST.MF文件中读取manifest.mf? - How to read manifest.mf from *.war/META-INF/MANIFEST.MF file? META-INF / MANIFEST.MF文件中的库依赖关系 - library dependencies in META-INF/MANIFEST.MF file Java - 即使 MANIFEST.MF 文件位于 /META-INF 中,App.jar 中也没有主要清单属性 - Java - No Main Manifest Attribute, in App.jar error even though MANIFEST.MF file is in /META-INF Aws Lambda访问META-INF / MANIFEST.MF? - Aws Lambda access to META-INF/MANIFEST.MF? jar文件中缺少主要属性,MANIFEST.MF文件位于META-INF文件夹中 - Missing main attribute inside the jar file, the MANIFEST.MF file is located in META-INF folder 对于 JIMAGE 文件,什么相当于 JAR 文件 META-INF/MANIFEST.MF? - What is the equivalent to JAR file META-INF/MANIFEST.MF for a JIMAGE file? 在unnamed.war中找不到META-INF / MANIFEST.MF文件 - META-INF/MANIFEST.MF file not found in unnamed.war 如何从 Spring Boot MVC Web 应用程序中的 META/MANIFEST.MF 读取数据? - How to read data from META/MANIFEST.MF in Spring Boot MVC Web Application? 为什么喜欢/ WEB-INF / lib到/META-INF/MANIFEST.MF用于webapps? - Why prefer /WEB-INF/lib to /META-INF/MANIFEST.MF for webapps? 提取和重新创建的jar不支持“ META-INF / MANIFEST.MF”中的清单。 - Extracted and recreated jar does not honor manifest at `META-INF/MANIFEST.MF`
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM