SpringBoot项目jar启动异常:java.io.FileNotFoundException: file:/xxx/xxx.jar!/BOOT-INF/classes!/xxx.yml

解决SpringBoot2.x项目中,使用旧版整合包导致的配置文件加载失败问题,通过修改配置文件读取方式及采用运行解压缩存档的部署方式,成功解决了资源路径错误引发的异常。

问题

最近公司项目要对接一个平台服务,项目是新建的,使用的是SpringBoot2.x,但对接平台给的整合包比较旧,2015开发的,整合进来发现存在一个问题:启动时找不到配置resources目录下的配置文件

异常内容如下:

java.io.FileNotFoundException: file:/xxx/project-xxx.jar!/BOOT-INF/classes!/xxx.yaml (No such file or directory)

很奇怪,检查了打包出来的jar,配置文件明明是存在的,为什么找不到呢?

于是,debug了一下出现问题的地方。

发现在平台给的整合包中,代码中读取配置文件的代码为:new FileInputStream(url.getPath())

这个问题就很好定位了,原因在于这种获取配置文件的方式无法获取压缩包中的配置文件。

解决方法

问题定位了,其实挺好解决,联系对方平台,将整合包中获取配置文件的代码修改一下,不要使用getResource或getFile方法来访问,而是使用获取文件流的方式,使用resource.getInputStream() 或getResourceAsStream()方法。

InputStream is=this.getClass().getResourceAsStream("xxx/xxx.yaml"); 
BufferedReader br=new BufferedReader(new InputStreamReader(is)); 

或者

Resource resource = new ClassPathResource("xxx/xxx.yaml");
InputStream inputStream = resource.getInputStream();

但是!对方怎么可能会改呢。。。

别问,问就是自己解决。但是我又不想改成war形式打包再放入web容器中启动的方式,于是我就查看了官方文档,看看有没有能解决这种问题的。

别说,还真有!在部署应用的章节中描述了这种运行解压缩存档,再启动相应的启动器的部署方式。

在这里插入图片描述
使用这种方式再测试了下代码,没有这个问题了。

至此,问题解决。

### 文件路径问题分析 在Docker环境中启动Java应用时,`java.io.FileNotFoundException` 通常出现在尝试访问JAR包内部文件时,特别是在使用 `File` 或 `FileInputStream` 直接操作资源路径时。这种问题的根本原因在于JavaJAR文件系统(`jar:file:/...`)与本地文件系统(`file:/...`)的行为差异,导致某些API(如 `File` 类)无法直接访问JAR内部资源[^1]。 例如,当使用如下方式访问资源时: ```java File file = new File("file:/work/app.jar!/BOOT-INF/classes!/files/03test.docx"); ``` 会抛出异常,因为 `File` 类无法解析JAR内部的路径结构。JAR包是一个压缩文件,内部资源不能直接作为 `File` 对象访问。类似问题在Spring框架中也可能出现,例如在使用 `ResourceLoader` 获取资源后调用 `.getFile()` 方法时。 ### 推荐解决方案 #### 使用 `InputStream` 或 `Resource` 接口访问资源 为了解决这个问题,应避免使用 `File` 类,而应使用 `InputStream` 或 `Resource` 接口来读取资源内容。这种方式适用于文件在类路径下(`classpath:`)或JAR包内的场景。 ```java @Autowired private ResourceLoader resourceLoader; public void readFile() throws IOException { Resource resource = resourceLoader.getResource("classpath:files/03test.docx"); try (InputStream is = resource.getInputStream()) { // 处理输入流 } } ``` #### 配置Spring以避免文件系统访问 某些库或框架(如FreeMarker)在加载模板时会尝试将资源转换为 `File` 对象,这在资源位于JAR中时会导致异常。为避免此类问题,可以配置Spring不优先使用文件系统访问: ```java @Bean public FreeMarkerConfigurer freeMarkerConfigurer() { FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); configurer.setPreferFileSystemAccess(false); // 禁用文件系统访问优先 configurer.setTemplateLoaderPath("classpath:/templates/"); return configurer; } ``` #### Docker部署时的文件挂载策略 在Docker部署Java应用时,若文件需要从外部访问(如上传、下载),应将宿主机的文件目录挂载到容器中,避免直接从JAR包内读取文件。例如,在Docker命令中使用 `-v` 参数进行目录挂载: ```bash docker run -d -v /host/files:/container/files -p 8080:8080 my-java-app ``` 这样,应用可以通过 `/container/files/03test.docx` 路径访问宿主机上的文件,而不会出现路径问题。 #### 构建和资源放置需注意 确保资源文件(如 `03test.docx`)确实存在于 `src/main/resources` 目录下,并在构建后被正确打包到 `BOOT-INF/classes/` 路径中。可以通过解压JAR包验证资源是否存在: ```bash jar tf app.jar | grep 03test.docx ``` 若资源未被正确包含,应检查 `pom.xml` 或 `build.gradle` 中的资源过滤配置,确保非文本资源(如 `.docx` 文件)不会被排除。 ###
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值