如何获取Spring Boot项目jar包内resources资源文件夹的路径
问题根因
src/main/resources仅为开发阶段的源码目录,Maven构建打包后该目录不会保留在最终的jar包内,resources下的所有文件会被归档到jar包的BOOT-INF/classes/路径下,属于jar包内部的嵌套资源,不是操作系统文件系统中的独立文件/目录,不可能通过Paths.get直接拿到对应文件系统的Path实例。- 第二种写法抛出空指针的两个原因:
- Spring Boot使用自定义的
LaunchedURLClassLoader加载应用内部的类和资源,ClassLoader.getSystemClassLoader()拿到的系统类加载器无法识别jar包内的应用资源,会直接返回null - 就算拿到了资源的URI,jar包内资源的URI格式为
jar:file:/xxx/your-app.jar!/BOOT-INF/classes/templates,Path.of仅支持file协议的URI,无法解析jar协议的资源地址,依然会报错
- Spring Boot使用自定义的
解决方案
根据你的使用场景选择对应实现:
场景1:仅需要读取资源内容,不需要拿到文件系统Path
推荐直接使用Spring官方提供的ResourceLoader,天然适配IDE、jar包等所有运行环境:
import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.stereotype.Component; @Component public class ResourceService { private final ResourceLoader resourceLoader; // Spring会自动注入ResourceLoader实例 public ResourceService(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } public void readTemplateResource() throws IOException { // classpath:前缀对应resources根目录,直接写相对路径即可 Resource templatesResource = resourceLoader.getResource("classpath:templates/"); // 直接获取输入流读取内容,不需要关心资源的实际存储形式 try (var inputStream = templatesResource.getInputStream()) { // 你的资源处理逻辑 } } }
场景2:必须拿到文件系统的Path实例(如需要遍历目录、修改资源等操作)
jar包内的嵌套资源无法直接映射为文件系统Path,需要先将资源解压到外部临时目录再操作:
public Path getTemplatesPath() throws IOException { Resource templatesResource = resourceLoader.getResource("classpath:templates/"); // 创建临时目录存放解压后的资源 Path tempDir = Files.createTempDirectory("app_templates_"); try { // IDE环境走文件系统路径直接复制 Path sourcePath = Path.of(templatesResource.getURI()); copyDirectory(sourcePath, tempDir); } catch (FileSystemNotFoundException e) { // jar环境走流读取解压 extractResourceToDir(templatesResource, tempDir); } return tempDir; } // 目录复制工具方法,可根据需要自行实现递归多层目录的逻辑 private void copyDirectory(Path source, Path target) throws IOException { Files.walk(source) .forEach(path -> { try { Path targetPath = target.resolve(source.relativize(path)); if (Files.isDirectory(path)) { Files.createDirectories(targetPath); } else { Files.copy(path, targetPath); } } catch (IOException ex) { throw new RuntimeException(ex); } }); } // jar环境资源解压工具方法,可根据实际资源结构调整 private void extractResourceToDir(Resource resource, Path targetDir) throws IOException { // 此处按你的实际资源结构实现流读取写入逻辑即可 }
注意事项
- 不要硬编码开发阶段的源码路径,该路径仅存在于你的工程源码目录,打包部署后完全不存在
- 不要直接使用系统类加载器读取Spring Boot应用的内部资源,Spring的
ResourceLoader已经屏蔽了不同运行环境的资源加载差异,是最优选择 - jar包内的资源默认是只读的,如果有资源修改需求,必须将资源存储到jar包外的独立目录(如应用工作目录、系统临时目录等)
内容的提问来源于stack exchange,提问作者Elmar Brauch
相关产品推荐
相关产品推荐

