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

Spring Boot胖JAR中读取嵌套JAR内配置文件问题

解决Spring Boot胖JAR中读取嵌套JAR内配置文件的问题

Spring官方解决方案

1. 使用Spring Boot Archive API(精准适配所有运行场景)

Spring Boot提供的Archive API专门用于处理胖JAR的内部结构,不管是通过java -jar运行打包后的JAR,还是用gradlew bootRun/maven命令运行开发模式,都能正确遍历BOOT-INF/lib下的嵌套JAR。

代码示例:

import org.springframework.boot.loader.archive.Archive;
import org.springframework.boot.loader.archive.JarFileArchive;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public void searchConfFiles() throws Exception {
    // 获取当前应用的Archive实例,自动适配打包JAR和开发模式
    Archive archive = new JarFileArchive(new File(System.getProperty("java.class.path").split(File.pathSeparator)[0]));

    // 过滤出BOOT-INF/lib下的所有嵌套JAR
    for (Archive nestedArchive : archive.getNestedArchives(entry -> entry.getName().startsWith("BOOT-INF/lib/"))) {
        if (nestedArchive instanceof JarFileArchive jarArchive) {
            try (JarFile jarFile = jarArchive.getJarFile()) {
                Enumeration<JarEntry> entries = jarFile.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    // 筛选出.conf后缀的非目录文件
                    if (!entry.isDirectory() && entry.getName().endsWith(".conf")) {
                        try (InputStream inputStream = jarFile.getInputStream(entry)) {
                            String content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
                            System.out.println("Found .conf file: " + URI.create("jar:" + jarArchive.getUrl() + "!/" + entry.getName()));
                            System.out.println(content);
                        }
                    }
                }
            }
        }
    }
}

2. 调整PathMatchingResourcePatternResolver的资源匹配规则

你原来的代码存在两个问题:

  • classpath:/只能访问当前类路径根目录,无法穿透嵌套JAR;
  • BOOT-INF/lib路径仅在打包后的胖JAR中存在,开发模式下类路径无此结构。

改用classpath*:前缀搭配通用路径,即可扫描所有类路径(包括嵌套JAR)中的.conf文件:

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

public void searchConfFiles() throws Exception {
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

    // 扫描所有类路径(含嵌套JAR)下的.conf文件
    Resource[] resources = resolver.getResources("classpath*:**/*.conf");

    System.out.println("resource length: " + resources.length);
    for (Resource resource : resources) {
        if (resource.exists()) {
            try (InputStream inputStream = resource.getInputStream()) {
                String content = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
                System.out.println("Found .conf file: " + resource.getURI());
                System.out.println(content);
            }
        }
    }
}

如果需要仅限定扫描BOOT-INF/lib下的嵌套JAR,Archive API是更精准的选择;若只需收集所有.conf文件,这个方法更简洁。

替代方案(不依赖Spring API)

如果不想依赖Spring Boot特定API,可以用Java原生的JarFile类直接遍历类路径下的所有JAR文件:

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public void searchConfFiles() throws IOException {
    String classPath = System.getProperty("java.class.path");
    String[] classPathEntries = classPath.split(File.pathSeparator);

    for (String entryPath : classPathEntries) {
        File file = new File(entryPath);
        // 遍历类路径下的所有JAR文件
        if (file.isFile() && entryPath.endsWith(".jar")) {
            try (JarFile jarFile = new JarFile(file)) {
                Enumeration<JarEntry> entries = jarFile.entries();
                while (entries.hasMoreElements()) {
                    JarEntry jarEntry = entries.nextElement();
                    if (!jarEntry.isDirectory() && jarEntry.getName().endsWith(".conf")) {
                        try (InputStream is = jarFile.getInputStream(jarEntry)) {
                            String content = new String(is.readAllBytes(), StandardCharsets.UTF_8);
                            System.out.println("Found .conf file: " + file.getAbsolutePath() + "!/" + jarEntry.getName());
                            System.out.println(content);
                        }
                    }
                }
            }
        }
    }
}

这个方法兼容性极强,适用于任何Java应用,无需依赖Spring生态。

内容的提问来源于stack exchange,提问作者Deepu Varma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:22:07