You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么Maven打包Jar时无法读取生成的MANIFEST.MF文件?

问题概述

你遇到的是Spring Boot可执行Jar包读取自定义MANIFEST.MF失败的问题,具体表现为:

  • 用类加载器读取META-INF/MANIFEST.MF只能拿到依赖包的清单,无法获取当前应用打包生成的清单
  • 使用ServletContext读取同样返回null
  • 手动将MANIFEST.MF放到resources/META-INF/下可以正常读取
  • 同配置的WAR包项目可以正常读取清单
问题原因
  • Spring Boot 可执行Jar采用了独立的分层归档结构,maven-jar-plugin生成的MANIFEST.MF默认存放在Jar包的根级META-INF/目录下,而Spring Boot内置的类加载器LaunchedURLClassLoader的类扫描范围仅包含BOOT-INF/classes/(应用编译类)和BOOT-INF/lib/(依赖Jar包),根级META-INF/不在类加载器的扫描路径内,所以你通过类加载器读取META-INF/MANIFEST.MF只能拿到依赖包的清单文件,拿不到当前应用的。
  • 你本地开发阶段通过IDE直接运行项目时,运行的是target/classes/下的编译文件,maven-jar-plugin的MANIFEST.MF是打包环节才生成的,不会出现在target/classes/META-INF/下,自然也读不到,你手动放到resources/META-INF/下的文件会被编译到该目录,所以可以正常读取。
  • 内置ServletContext的资源扫描范围和类加载器对齐,仅覆盖BOOT-INF/classes/、BOOT-INF/lib/下的静态资源路径,不会映射Jar包根目录的META-INF/,所以你用ServletContext读取也返回null。
  • WAR包的场景是符合Servlet规范的标准归档结构,根级META-INF/属于ServletContext的扫描范围,所以可以正常读取。
  • 注意:你原配置中<Custom-Entry>的闭合标签存在笔误,写为了</CustomEntry>,缺失横杠,会导致自定义字段无法正常生成到MANIFEST.MF中
解决方案

方案1(推荐,适配本地开发+Jar包运行全场景)

将生成的MANIFEST.MF输出到类路径下,适配类加载器的扫描规则:

  1. 在src/main/resources/下创建空的META-INF/目录
  2. 调整maven-jar-plugin配置,新增outputDirectory配置将生成的清单文件输出到编译类路径:
<plugin>
   <artifactId>maven-jar-plugin</artifactId>
   <version>${maven.jar.version}</version>
   <configuration>
      <archive>
         <addMavenDescriptor>false</addMavenDescriptor>
         <manifest>
            <addClasspath>true</addClasspath>
            <classpathPrefix>lib/</classpathPrefix>
            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
            <packageName>${project.artifactId}-${project.version}</packageName>
         </manifest>
         <manifestEntries>
            <!-- 修正闭合标签的笔误 -->
            <Custom-Entry>someValue</Custom-Entry>
         </manifestEntries>
      </archive>
      <!-- 新增配置,将生成的MANIFEST.MF输出到编译类路径 -->
      <outputDirectory>${project.build.outputDirectory}</outputDirectory>
   </configuration>
</plugin>

配置完成后,可直接通过类加载器读取:

InputStream is = this.getClass().getClassLoader().getResourceAsStream("META-INF/MANIFEST.MF");

方案2(仅适配Jar包运行场景)

直接读取当前运行的Jar包根目录的MANIFEST.MF,代码示例:

public Manifest getCurrentJarManifest() throws Exception {
    // 获取当前运行程序的代码源路径
    File codeSource = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI());
    // 仅Jar包运行时生效,IDE运行时返回classes目录,可自行添加兼容逻辑
    if (codeSource.isFile() && codeSource.getName().endsWith(".jar")) {
        try (JarFile jarFile = new JarFile(codeSource)) {
            return jarFile.getManifest();
        }
    }
    return null;
}

内容的提问来源于stack exchange,提问作者Aleksey Gareev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 16:45:01