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

Maven打包含依赖可执行Jar时,META-INF文件致外部conf资源加载失败

问题

我尝试用Maven构建包含所有依赖的可执行Jar包,同时指定ClassPath加载外部conf目录的资源。当前的maven-assembly-plugin配置如下:

...
<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals><goal>single</goal></goals>
        </execution>
    </executions>
    <configuration>
        <appendAssemblyId>false</appendAssemblyId>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive>
            <manifestEntries>
                <Version>${project.version}</Version>
                <Class-Path>conf/</Class-Path>
                <Main-Class>${exec.mainClass}</Main-Class>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>
...

生成的Jar包中MANIFEST.MF内容如下:

Manifest-Version: 1.0
Created-By: Maven Archiver 3.6.1
Build-Jdk-Spec: 17
Class-Path: conf/
Main-Class: gina.report.Main
Version: 2.0.0

现在遇到的问题是:Jar包的/META-INF目录下生成了大量额外文件和目录,删除这些文件只保留MANIFEST.MF时,程序能正常加载conf目录的资源;但保留这些文件时,ClassLoader就无法加载该目录下的资源。请问这是什么原因?

原因分析与解决方案

核心原因

使用jar-with-dependencies描述符打包时,maven-assembly-plugin会把所有依赖Jar的内容解压合并到最终Jar中,包括依赖Jar里/META-INF目录下的文件(比如INDEX.LIST、services/目录、依赖自身的MANIFEST.MF等)。

其中**INDEX.LIST是关键问题**:这个文件是JAR资源索引,由Jar工具生成,记录了Jar内部所有资源路径。JVM加载Jar时,如果存在这个文件,会优先用它查找资源,完全跳过Class-Path指定的外部目录,导致conf目录的资源被ClassLoader忽略。

解决方法

方法1:自定义Assembly描述符,排除不必要的META-INF文件

放弃直接使用jar-with-dependencies,自己编写assembly描述符文件(如src/main/assembly/assembly.xml),明确排除INDEX.LIST及冗余签名文件:

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
    <id>jar-with-dependencies</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>runtime</scope>
            <excludes>
                <exclude>META-INF/INDEX.LIST</exclude>
                <exclude>META-INF/*.SF</exclude>
                <exclude>META-INF/*.DSA</exclude>
                <exclude>META-INF/*.RSA</exclude>
            </excludes>
        </dependencySet>
    </dependencySets>
    <archive>
        <manifestEntries>
            <Version>${project.version}</Version>
            <Class-Path>conf/</Class-Path>
            <Main-Class>${exec.mainClass}</Main-Class>
        </manifestEntries>
    </archive>
</assembly>

然后修改pom.xml中的插件配置,指定自定义描述符:

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals><goal>single</goal></goals>
            <configuration>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptors>
                    <descriptor>src/main/assembly/assembly.xml</descriptor>
                </descriptors>
            </configuration>
        </execution>
    </executions>
</plugin>

方法2:替换为maven-shade-plugin

maven-shade-plugin打包可执行Jar时,默认不会生成INDEX.LIST,还能智能合并META-INF下的服务配置文件,避免冲突。配置示例:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.4.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals><goal>shade</goal></goals>
            <configuration>
                <shadedArtifactAttached>false</shadedArtifactAttached>
                <shadedClassifierName>jar-with-dependencies</shadedClassifierName>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <manifestEntries>
                            <Version>${project.version}</Version>
                            <Class-Path>conf/</Class-Path>
                            <Main-Class>${exec.mainClass}</Main-Class>
                        </manifestEntries>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

内容的提问来源于stack exchange,提问作者Maurice Perry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 17:13:09